package com.cci.kangdao.service.impl;

import com.alibaba.fastjson.JSON;
import com.cci.kangdao.aop.UserThreadLocal;
import com.cci.kangdao.common.RedisKeys;
import com.cci.kangdao.common.type.MarketClassType;
import com.cci.kangdao.common.type.OverTimeType;
import com.cci.kangdao.crmapi.CRMApiUtils;
import com.cci.kangdao.crmapi.CRMResponeEntity;
import com.cci.kangdao.crmapi.CRMServiceConst;
import com.cci.kangdao.dao.*;
import com.cci.kangdao.dao.model.*;
import com.cci.kangdao.entity.CampaignTaskFlow;
import com.cci.kangdao.entity.LatestWorkOrder;
import com.cci.kangdao.redis.RedisClientUtils;
import com.cci.kangdao.service.PropertiesUtils;
import com.cci.kangdao.service.WorkOrderRepairService;
import com.cci.kangdao.service.WorkOrderSynchroService;
import com.cci.kangdao.task.AsyncTask;
import com.cci.kangdao.task.ThreadTask;
import com.cci.kangdao.utilTool.*;
import com.cci.kangdao.wechatOrder.service.IOrderPushMessageService;
import com.cci.kangdao.xgj.XGJBasicResponse;
import com.cci.kangdao.xgj.XgjApiConst;
import net.sf.json.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;

@Service("WorkOrderRepairService")
public class WorkOrderRepairServiceImpl implements WorkOrderRepairService{
    private Logger log = Logger.getLogger(this.getClass().getName());

	@Resource
	private WorkOrderRepairDao workOrderRepairDao;

	@Resource
	private CRMPlatformServiceDao platformServiceDao;

	@Resource
	private LoginDao loginDao;

	@Autowired
	private RedisClientUtils redisClientUtils;

	@Resource
	private EngineMsgDao engineMsgDao;

    @Resource
    private WorkOrderOverTimeDao workOrderOverTimeReasonDao;

    @Resource
    private WorkOrderReasonDao workOrderReasonDao;

    @Resource
    private WorkOrderTDao workOrderTDao;

    @Autowired
    private CompanyTDao companyTDao;

    @Resource
    private WorkOrderOperatorRelationDao workOrderOperatorRelationDao;

    @Resource
    private UserTDao userTDao;

    @Resource
    private RelationShipTDao relationShipTDao;

    @Resource
    private DBURemindTaskTDao dbuRemindTaskTDao;
    @Resource
    private PropertiesUtils propertiesUtils;
    @Resource
    private IOrderPushMessageService iOrderPushMessageService;
    @Resource
    private ServiceStationDao serviceStationDao;
    @Resource
    private WhiteListTDao whiteListTDao;

	@Resource
	private AsyncTask asyncTask;
    @Resource
    private WorkOrderFlowTDao workOrderFlowTDao;
    @Resource
    private WorkOrderSynchroService workOrderSynchroService;
    @Resource
    private CampaignTaskInfoDao campaignTaskInfoDao;
    @Resource
    private CampaignTaskFlowDao campaignTaskFlowDao;

    @Value("${xgjWorkOrder.api.url}")
    private String xgjUrl;

    @Value("${xgjWorkOrder.wwid}")
    private String wwid;

    @Value("${xgjWorkOrder.token}")
    private String token;


    private String msgbody = "您有新工单信息，工单号 ***，请尽快处理！";
    private String msgtitle = "新工单提醒";
    private String transmsg = "您有新工单信息，工单号 ***，请尽快处理！";
    private String msgbodyCCEC = "您有工单待400审核，工单号%s，请尽快处理！";
    private String transmsgCCEC = "您有工单待400审核，工单号%s，请尽快处理！";
    private String serviceStationMsgBody = "您有新工单信息，工单号%s，请尽快处理。";

    private String cmsgbody = "您有工单取消，工单号 ***，";
    private String cmsgtitle = "工单取消";
    private String ctransmsg = "您有工单取消，工单号 ***，";
    private String cmsgbodyCCEC = "您有工单取消，工单号%s，请查看！";
    private String ctransmsgCCEC = "您有工单取消，工单号%s，请查看！";
    private String xcecSaleAreaManagerMsg = "国六售时外出审批提醒：%s服务商，工单号%s，现有外出未审批，请尽快处理!";
    /**
     * sprint18: 【短信通知】【XCEC】区域经理接收国六故障提醒
     * 区域经理接收国六故障提醒短信，
     * ①短信模板：国六故障提醒：XXX服务商，工单号xxx,发动机序列XXX，现有国六服务审批请尽快处理
     * ②发送机制：工单提交时判断“发动机序列”为X12和M15系列,视为国6机型，则实时发送提醒短信；判断发动机序列条件项支持后台扩展，例如现在判断X12、15N，后续陆续会增加或删除新的发动机序列。
     */
    private String xcecGuoLiuTitle = "国六故障提醒";
    private String xcecGuoLiuStr = "国六故障提醒：%s服务商，工单号%s,发动机序列%s，现有国六服务审批请尽快处理";

    // sprint18 XCEC外出审批消息格式更新
    private String xcecOverTimeBody = "外出审批提醒：%s服务商，工单号%s，外出里程%skm，请尽快审批。";

    private int msgFunctionNew = 1;//字典项(用户在线报修修提醒)
    private int msgCategoryNew = 1;//字典项（新工单提醒）

    private int msgFunctionCancel = 9;//字典项(取消工单提醒)
    private int msgCategoryCancel = 4;//字典项（取消工单提醒）


    /**
     * 用户报修在线工单生成
     * 工单生成完毕-》记录用户行为-》同步至CRM工单信息？
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public ModelAndView customerCreateWorkOrder(Map<String, Object> map) {
        HttpServletResponse response = (HttpServletResponse) map.get("response");
        try {
            //2.10.0需求   对维修地址做长度限制   250个字
            String location = MapUtils.getString(map, "Location", "");
            if (location.length() > 250) {
                ParameterTool.writeResponse(response, SMSEnum.type605.getIndex(), SMSEnum.type605.getName());
                return null;
            }
            //工单来源   字典项
            int orderSource = MapUtils.getIntValue(map, "OrderSource", 0);
            String serviceChannel = MapUtils.getString(map, "OrderChannelName", "DCEC");
            String procurementTime = "";  //采购日期
            double distance = MapUtils.getDoubleValue(map, "GuessDistance", 0);
            //XCEC 所需的工单类型   故障地点省份和市
            int orderType = 0;//（0:发动机维修   1:售时服务）
            String province = MapUtils.getString(map, "Province", "");
            String city = MapUtils.getString(map, "City", "");
            map.put("OrderType", orderType);
            // 用户报修
            UserT userT = UserThreadLocal.get();   //当前登录人
            //CCEC渠道时CustomerPhone和CustomerName都是现场联系人手机号和现场联系人名称   在下面需要做转换
            String phone = MapUtils.getString(map, "CustomerPhone", userT.getPhone());
            map.put("CustomerPhone", phone);
            List<UserT> customerList = loginDao.getUserByPhone(phone);
            if (CollectionUtils.isNotEmpty(customerList)) {
                map.put("CustomerId", customerList.get(0).getId());  //往map中加入客户id字段对应的值
            }
            map.put("CustomerName", MapUtils.getString(map, "CustomerName", userT.getContact()));
            //ccec客户手机，id和姓名是当前登录人    现场人姓名手机号是前端传的CustomerPhone和CustomerName字段值
            if ("CCEC".equals(serviceChannel)) {
                //赋值现场联系人名字和电话,手机号
                map.put("ContactName", MapUtils.getString(map, "CustomerName", ""));
                map.put("ContactPhone", MapUtils.getString(map, "CustomerPhone", ""));
                map.put("CustomerPhone", userT.getPhone());
                map.put("CustomerName", userT.getContact());
                map.put("CustomerId", userT.getId());
            }
            map.put("ProcessorId", userT.getId());
            map.put("ProcessorName", userT.getContact());

            //保存工单返回结果
            int saveresult = -1;
            //查看报修发动机号当日是否已报修过，如果已经报修过，不可二次报修
            String ESN = MapUtils.getString(map, "ESN", "");
            String amtNo = MapUtils.getString(map, "AmtNo", "");

            if (StringUtils.isEmpty(ESN) && StringUtils.isEmpty(amtNo)) {
                ParameterTool.writeResponse(response, SMSEnum.type17.getIndex(), SMSEnum.type17.getName());
                return null;
            } else {
                String currentTime = LocalTimeUtil.getRealCurrentTime();
                currentTime = currentTime.substring(0, 10);
                map.put("currentTime", currentTime);
                //根据发动机号，查询工单表当日是否存在此发动机报修信息
                if (!(serviceChannel.equals("XCEC") || serviceChannel.equals("CCEC"))) {  //XCEC和CCEC同一个esn同一天没有限制报单次数
                    int ESNCount = 0;
                    if (StringUtils.isNotBlank(ESN)) {
                        ESNCount = workOrderRepairDao.getESNCount(map);
                    }
                    int amtNoCount = 0;
                    if (StringUtils.isNotBlank(amtNo)) {
                        amtNoCount = workOrderRepairDao.getAmtNoCount(map);
                    }
                    if (ESNCount + amtNoCount > 0) {
                        if (ESNCount > 0) {
                            //返回客户
                            ParameterTool.writeResponse(response, SMSEnum.type30.getIndex(), SMSEnum.type30.getName());
                        }
                        if (amtNoCount > 0) {
                            //返回客户
                            ParameterTool.writeResponse(response, SMSEnum.type37.getIndex(), SMSEnum.type37.getName());
                        }
                        return null;
                    }
                }
                if (serviceChannel.equals("XCEC")) {
                    //xcec增加校验 在APP系统是否存在未完成工单（工单状态!=服务完成、待用户评价、异常关闭、已取消） 2.9.0运维需求
                    Map<String, Object> orderMsgMap = workOrderTDao.getOrderMsgByESN(4, Arrays.asList(14,13,16,15), ESN);
                    if (MapUtils.isNotEmpty(orderMsgMap)) {
                        String noFinishWorkOrderNo = MapUtils.getString(orderMsgMap, "workOrderNo", "");
                        if (StringUtils.isNotEmpty(noFinishWorkOrderNo)) {
                            ParameterTool.writeResponse(response, 30, "此ESN存在未完成工单，工单号:" + noFinishWorkOrderNo);
                            return null;
                        }
                    }
                }
            }
            String currentTime = LocalTimeUtil.getRealCurrentTime();
            //后台自动生成工单编号
            /**
             * <p>
             *     自动生成工单编号，由 redis 更改为 sqlserver
             * </p>
             */
            //String OrderNo = getOrderNo(map);
            String OrderNo = OrderGenerateUtil.getWorkOrderNo();
            map.put("OrderNo", OrderNo);
            String fwOrderNo = "";//crmNo   下面同步给crm后   crm会返回

            // 工单创建人ID
            map.put("Creator", map.get("ProcessorId"));
            // 工单生成时间
            map.put("CreateTime", currentTime);
            // 工单更新人
            map.put("Updator", map.get("ProcessorId"));
            // 工单更新时间（修改工单判断条件之一）
            map.put("UpdateTime", currentTime);
            // 用户保存插入工单成功返回的工单ID
            map.put("OrderId", "");

            // DBU渠道通过EngineMsgId拼装市场类型，应用程序，保修起始日
            if ("CCI".equals(serviceChannel)) {
                Long engineMsgId = MapUtils.getLong(map, "EngineMsgId", 0L);
                EngineMsg engineMsg = engineMsgDao.getEngineMsgById(engineMsgId);
                if (null != engineMsg) {
                    map.put("MarketType", engineMsg.getMarketType());
                    map.put("Application", engineMsg.getApplication());
                    String warrantyStartDate = engineMsg.getWarrantyStartDate();
                    if (StringUtils.isNotEmpty(warrantyStartDate)) {
                        // 处理发动机信息表DBU无法处理的保修起始日数据
                        if (warrantyStartDate.contains("/")) {
                            warrantyStartDate = warrantyStartDate.replace("/", "-");
                        }
                    }
                    map.put("WarrantyStartDate", warrantyStartDate);
                    map.put("manufactor", engineMsg.getManufactor());
                }
            }

            //保存该服务站区域服务经理(DCEC,XCEC)  区域工程师(DBU)  400人员(CCEC)的信息
            List<Map<String, Object>> AreaManagerMap = new ArrayList<>();
            //保存该服务站的站长的信息
            List<UserT> zzList = new ArrayList<>();
            //保存该服务站的信息员的信息
            List<UserT> xxyList = new ArrayList<>();
            Map<String, Object> engineMsg;
            if(serviceChannel.equals("DCEC")&&StringUtils.isNotBlank(amtNo)){
                engineMsg = engineMsgDao.getSMNByAmtNo(amtNo);
            }else {
                engineMsg = engineMsgDao.getSMNByESN(ESN);
            }
            //判断用户是否已选择服务站
            String serviceStationId = MapUtils.getString(map, "ServiceStationId", "");
            if (StringUtils.isEmpty(serviceStationId)) {
                // 用户未选择服务站，直接生成用户工单(此时工单没有负责人)
                // 填充工单状态（用户报修但未选择服务站，工单状态为  已创建：1）
                map.put("OrderStatus", "1");
                if (serviceChannel.equals("CCEC")) {
                    //没选择服务站   就判断是否有400审核人员
                    AreaManagerMap = workOrderRepairDao.getCCECAreaManager(MapUtils.getLongValue(map, "OrderChannel"));
                    if (CollectionUtils.isEmpty(AreaManagerMap)) {
                        //未查询到相关审核人信息
                        ParameterTool.writeResponse(response, SMSEnum.type23.getIndex(), SMSEnum.type23.getName());
                        return null;
                    }
                    //如果服务渠道是CCEC，
                    map.put("OrderStatus", "23");
                    map.put("CustomerCompanyName", MapUtils.getString(map, "CustomerCompany", ""));
                }
                if (serviceChannel.equals("DCEC") && StringUtils.isBlank(amtNo)) {
                    map.put("WarrantyNature", "发动机保修");
                }
                //无app保修
                String warrantyNature = MapUtils.getString(map, "WarrantyNature");
                if (serviceChannel.equals("DCEC") && StringUtils.isNotBlank(warrantyNature) && "变速箱保修".equals(warrantyNature) && StringUtils.isNotBlank(amtNo)) {
                    orderType = 3;
                    map.put("OrderType", orderType);
                }
                //没有smn从数据库获取
                if((!map.containsKey("SMN") || StringUtils.isEmpty(MapUtils.getString(map, "SMN", ""))) && MapUtils.isNotEmpty(engineMsg)){
                    map.put("SMN",MapUtils.getString(engineMsg, "SMN", ""));
                }
                //根据高德获取地址
                String locLon = MapUtils.getString(map, "LocLon");
                String locLat = MapUtils.getString(map, "LocLat");
                if (StringUtils.isNotBlank(locLon)&&StringUtils.isNotBlank(locLat)) {
                    Map<String, Object> reginInfo = null;
                    if (MapUtils.getDouble(map, "LocLon") < 60) { // APP操作同步，非重传，参数需要座处理
                        reginInfo = GDRegion.getReginInfo(locLon,locLat);
                    }else {
                        reginInfo = GDRegion.getReginInfo(locLat,locLon);
                    }
                    if (reginInfo!=null) {
                        if (StringUtils.isNotBlank(MapUtils.getString(reginInfo,"province"))) {
                            map.put("Province",reginInfo.get("province"));
                        }
                        if (StringUtils.isNotBlank(MapUtils.getString(reginInfo,"city"))) {
                            map.put("City",reginInfo.get("city"));
                        }
                        if (StringUtils.isNotBlank(MapUtils.getString(reginInfo,"location"))) {
                            map.put("Location",reginInfo.get("location"));
                        }
                    }
                }

                saveresult = workOrderRepairDao.CreateWorkOrder(map);
                // 将工单信息同步至CRM接口
                // 字段转换（APP接口字段名与CRM接口字段名不一致。）
                Map<String, Object> tbMap = APP2CRM_WorkOrder_Convert(map, orderSource, serviceChannel);
                tbMap.put("orderType", orderType);
                tbMap.put("city", city);
                tbMap.put("province", province);
                if (MapUtils.isNotEmpty(engineMsg)) {
                    procurementTime = MapUtils.getString(engineMsg, "ShoppingDate", "");
                }
                tbMap.put("procurementTime", procurementTime);
                tbMap.put("isInsured", MapUtils.getString(engineMsg, "ISWarrantyStart"));
                tbMap.put("estimateWarrantyStartDate", MapUtils.getString(engineMsg, "EstimateWarrantyStartDate"));
                tbMap.put("contactName", MapUtils.getString(map, "ContactName"));
                tbMap.put("contactPhone", MapUtils.getString(map, "ContactPhone"));
                tbMap.put("requestType", MapUtils.getString(map, "RequestType"));
                tbMap.put("faultLevel", MapUtils.getString(map, "FaultLevel"));
                tbMap.put("sizeFailure", MapUtils.getString(map, "SizeFailure"));
                tbMap.put("repairerType", MapUtils.getString(map, "RepairerType"));
                //是否代他人报修   ccec
                if ("CCEC".equals(serviceChannel)) {
                    tbMap.put("isInsteadRepairs", MapUtils.getString(map, "IsInsteadRepairs", ""));
                }
				try {
					CRMResponeEntity CRMres = CRMApiUtils.getCRMServiceApi().syncAppOrderInfoToCRM(serviceChannel,platformServiceDao,redisClientUtils,tbMap,null);
					if(CRMres.getStatus()!=0) {
						//APP同步工单信息到CRM系统失败
						log.error("用户在线报修同步工单信息至CRM失败，状态："+CRMres.getStatus()+"，用户信息:"+CRMres.getMessage());
					}else{
						//fwOrderNo = String.valueOf(CRMres.getData().get("CCSSOrderNo"));
						if(CRMres.getData().containsKey("CCSSOrderNo")){
							fwOrderNo = CRMres.getData().getString("CCSSOrderNo");
						}
					}
				} catch (Exception e) {
					//APP同步工单信息到CRM系统失败
					log.error("用户在线报修同步工单信息至CRM失败："+e.getMessage(),e);
				}
			}else {
				//处理服务站Id,CCI需求用户无服务站选择，所以这里全是DCEC，XCEC和CCEC的数据
				map.put("ServiceStationId", AESTool.decryptString(map.get("ServiceStationId").toString()));
				//XCEC用户报修选择了服务站
				map.put("ServiceStationID", map.get("ServiceStationId"));
				// dcec渠道新需求，APP端审批权限及范围有变更 由原外出里程大于90KM审批更改为100KM
				if(("XCEC".equals(serviceChannel) && distance < 300) || "CCEC".equals(serviceChannel) ||("DCEC".equals(serviceChannel) && distance < 100)){
					//xcec用户报单选择了服务站   并且外出里程小于300
					// dcec用户报单选择了服务站   并且外出里程小于90
                    //CCEC渠道  如果服务站id不为空   则肯定是非保修类服务   负责人是站长和信息员   工单状态为待服务商接单
                    zzList = userTDao.getUserTByServiceStationId(map);
                    xxyList = userTDao.getMsgUserTByServiceStationId(map);
                    //XCEC用户选择了服务站且里程小于300（工单状态默认为：待服务商接单）
                    map.put("OrderStatus", "4");
                    map.put("AssignStationTime", currentTime);
                } else {
                    // 用户在线报修选择了服务站（此时工单负责人就是该服务站的区域服务经理）
                    // 根据服务站Id查询服务站的区域服务经理(用户在线保修选择服务站，工单创建完成，工单负责人就是区域服务经理，且为主负责人)
                    AreaManagerMap = workOrderRepairDao.getAreaManager(map);
                    if (CollectionUtils.isEmpty(AreaManagerMap)) {
                        //未查询到相关审核人信息
                        ParameterTool.writeResponse(response, SMSEnum.type23.getIndex(), SMSEnum.type23.getName());
                        return null;
                    }
                    // 暂未发现roleNo使用，保留代码而已
                    map.put("roleNo", "'R0070'");
                    //用户选择了服务站（工单状态默认为：待服务经理确认）
                    map.put("OrderStatus", "2");
                }
                if ("CCEC".equals(serviceChannel)) {
                    map.put("CustomerCompanyName", MapUtils.getString(map, "CustomerCompany", ""));
                }
                /**
                 * 2023-1-17 新增 DCEC 终端用户报修的发动机工单，【保修性质】默认赋值：发动机保修
                 */
                if (serviceChannel.equals("DCEC") && StringUtils.isBlank(amtNo)) {
                    map.put("WarrantyNature", "发动机保修");
                }
                //amt工单  报单
                String warrantyNature = MapUtils.getString(map, "WarrantyNature");
                if (serviceChannel.equals("DCEC") && StringUtils.isNotBlank(warrantyNature) && "变速箱保修".equals(warrantyNature) && StringUtils.isNotBlank(amtNo)) {
                    orderType = 3;
                    map.put("OrderType", orderType);
                }
                saveresult = workOrderRepairDao.CreateWorkOrder(map);
                // 将工单信息同步至CRM接口
                // 字段转换（APP接口字段名与CRM接口字段名不一致。）
                Map<String, Object> tbMap = APP2CRM_WorkOrder_Convert(map, orderSource, serviceChannel);
                tbMap.put("orderType", orderType);
                tbMap.put("city", city);
                tbMap.put("province", province);
                tbMap.put("procurementTime", procurementTime);
                if (MapUtils.isNotEmpty(engineMsg)) {
                    procurementTime = MapUtils.getString(engineMsg, "ShoppingDate", "");
                }
                tbMap.put("procurementTime", procurementTime);
                tbMap.put("isInsured", MapUtils.getString(engineMsg, "ISWarrantyStart"));
                tbMap.put("estimateWarrantyStartDate", MapUtils.getString(engineMsg, "EstimateWarrantyStartDate"));
                tbMap.put("contactName", MapUtils.getString(map, "ContactName"));
                tbMap.put("contactPhone", MapUtils.getString(map, "ContactPhone"));
                tbMap.put("requestType", MapUtils.getString(map, "RequestType"));
                tbMap.put("faultLevel", MapUtils.getString(map, "FaultLevel"));
                tbMap.put("sizeFailure", MapUtils.getString(map, "SizeFailure"));
                tbMap.put("repairerType", MapUtils.getString(map, "RepairerType"));
                //是否代他人报修   ccec
                if ("CCEC".equals(serviceChannel)) {
                    tbMap.put("isInsteadRepairs", MapUtils.getString(map, "IsInsteadRepairs", ""));
                }
                try {
                    CRMResponeEntity CRMres = CRMApiUtils.getCRMServiceApi().syncAppOrderInfoToCRM(map.get("OrderChannelName").toString(), platformServiceDao, redisClientUtils, tbMap,null);
                    if (CRMres.getStatus() != 0) {
                        //APP同步工单信息到CRM系统失败
                        log.error("用户在线报修同步工单信息至CRM失败，状态：" + CRMres.getStatus() + "，用户信息:" + CRMres.getMessage());
                    } else {
                        //fwOrderNo = String.valueOf(CRMres.getData().get("CCSSOrderNo"));
                        if (CRMres.getData().containsKey("CCSSOrderNo")) {
                            fwOrderNo = CRMres.getData().getString("CCSSOrderNo");
                        }
                    }
                } catch (Exception e) {
                    // APP同步工单信息到CRM系统失败
                    log.error("用户在线报修同步工单信息至CRM失败：" + e.getMessage(), e);
                }
            }

            //记录创建工单记录（（需要把上面保存成功的工单Id放进map中））
            if (saveresult > 0) {
                workOrderRepairDao.saveOperation(map);
                // 保存工单负责人信息
                if (StringUtils.isNotEmpty(serviceStationId)) {
                    //XCEC   外出里程小于300   负责人是站长和信息员
                    //ccec如果指派了服务站  负责人一定是站长信息员
                    // DCEC   外出里程小于90    负责人是站长和信息员
					if("XCEC".equals(serviceChannel) && distance < 300 || "CCEC".equals(serviceChannel) || ("DCEC".equals(serviceChannel) && distance < 100)){   //XCEC   外出里程小于300   负责人是站长和信息员
						if(CollectionUtils.isNotEmpty(zzList)){
							for(UserT userT1 : zzList) {
								map.put("PrincipalId", userT1.getId());
								map.put("IsPrincipal", 1);
								workOrderRepairDao.savePrincipal(map);
							}
						}
						if(CollectionUtils.isNotEmpty(xxyList)){
							for(UserT userT1 : xxyList) {
								map.put("PrincipalId", userT1.getId());
								map.put("IsPrincipal", 1);
								workOrderRepairDao.savePrincipal(map);
							}
						}
					}else{   //其他服务渠道和XCEC外出里程大于300负责人都是区域服务经理
						if(CollectionUtils.isNotEmpty(AreaManagerMap)){
							for(Map<String,Object> amap : AreaManagerMap) {
								map.put("PrincipalId", amap.get("ID"));
								map.put("IsPrincipal", 1);
								workOrderRepairDao.savePrincipal(map);
							}
						}
					}
				}else{
					//ccec用户报单没有选择服务站    负责人是400
					if("CCEC".equals(serviceChannel) && CollectionUtils.isNotEmpty(AreaManagerMap)){
						for(Map<String,Object> amap : AreaManagerMap) {
							map.put("PrincipalId", amap.get("ID"));
							map.put("IsPrincipal", 1);
							workOrderRepairDao.savePrincipal(map);
						}
					}
				}

				//工单保存成功，给相应人员发送消息，并记录发送记录
				if(StringUtils.isEmpty(serviceStationId)) {
					// 如果用户在线保修时未选择服务站，则区域服务经理发送APP消息与短信(400派单后再发送，此逻辑不在这里做)
					//CCEC渠道用户报修没有选择服务站  给400推送消息
					//准备发送信息
					if("CCEC".equals(serviceChannel)){
						List<Map<String,Object>> sendList = new ArrayList<>(AreaManagerMap);
						Map<String,Object> otherMap = new HashMap<String,Object>();
						String smsgbody = msgbodyCCEC;
						String stransmsg = transmsgCCEC;
						String msg = "";
						if(StringUtils.isNotEmpty(fwOrderNo)){
							msg = OrderNo+ "（FW号"+ fwOrderNo +"）";
							smsgbody = String.format(smsgbody, msg);
							stransmsg = String.format(stransmsg, msg);
						}else{
							smsgbody = String.format(smsgbody, OrderNo);
							stransmsg = String.format(stransmsg, OrderNo);
						}
						otherMap.put("msgBody", smsgbody);//(,,,,)
						otherMap.put("msgTransMsg", stransmsg);
						otherMap.put("msgTitle", msgtitle);
						otherMap.put("function", msgFunctionNew);
						otherMap.put("category", msgCategoryNew);
						//开始发送消息(返回结果集为发送结果，要存入数据库，作为记录)
						List<Map<String,Object>> sendMsgResultList = asyncTask.sendMsg(map,sendList,1,1,otherMap);
						//将信息发送结果记录到数据库
						if(CollectionUtils.isNotEmpty(sendMsgResultList)){
							workOrderRepairDao.saveMsgOperation(sendMsgResultList);
						}
					}
				}else {
					if(("XCEC".equals(serviceChannel) && distance < 300) || "CCEC".equals(serviceChannel) || ("DCEC".equals(serviceChannel) && distance < 100)){
						//XCEC   外出里程小于300   负责人是站长和信息员
						//DCEC   外出里程小于90    负责人是站长和信息员
						//准备发送信息
						Map<String,Object> otherMap = new HashMap<String,Object>();
						String smsgbody = "";
						String stransmsg = "";
						String msg = "";
						if("CCEC".equals(serviceChannel)){
							smsgbody = serviceStationMsgBody;
							stransmsg = serviceStationMsgBody;
							if(StringUtils.isNotEmpty(fwOrderNo)){
								msg = OrderNo+ "（FW号"+ fwOrderNo +"）";
								smsgbody = String.format(smsgbody, msg);
								stransmsg = String.format(stransmsg, msg);
							}else{
								smsgbody = String.format(smsgbody, OrderNo);
								stransmsg = String.format(stransmsg, OrderNo);
							}
						}else{
							smsgbody = msgbody;
							stransmsg = transmsg;
							smsgbody = smsgbody.replace("***", OrderNo);
							stransmsg = stransmsg.replace("***", OrderNo);
						}
						otherMap.put("msgBody", smsgbody);//(,,,,)
						otherMap.put("msgTransMsg", stransmsg);
						otherMap.put("msgTitle", msgtitle);
						otherMap.put("function", msgFunctionNew);
						otherMap.put("category", msgCategoryNew);
						//开始发送消息(返回结果集为发送结果，要存入数据库，作为记录)
						List<Map<String,Object>> sendList = new ArrayList<>();
						if(CollectionUtils.isNotEmpty(zzList)){
							for(UserT userT1 : zzList) {
								Map<String,Object> sendMap = new HashMap<>();
								//ut.ID,ut.UserName,ut.phone,rst.clientId
								sendMap.put("ID",userT1.getId());
								sendMap.put("UserName",userT1.getUserName());
								sendMap.put("phone",userT1.getPhone());
								RelationShipT relationShipT = relationShipTDao.getClientIdByUserNameString(userT1.getUserName());
								if(null != relationShipT){
									sendMap.put("clientId",relationShipT.getClientId());
								}else{
									sendMap.put("clientId","");
								}
								sendList.add(sendMap);
							}
						}
						if(CollectionUtils.isNotEmpty(xxyList)){
							for(UserT userT1 : xxyList) {
								Map<String,Object> sendMap = new HashMap<>();
								//ut.ID,ut.UserName,ut.phone,rst.clientId
								sendMap.put("ID",userT1.getId());
								sendMap.put("UserName",userT1.getUserName());
								sendMap.put("phone",userT1.getPhone());
								RelationShipT relationShipT = relationShipTDao.getClientIdByUserNameString(userT1.getUserName());
								if(null != relationShipT){
									sendMap.put("clientId",relationShipT.getClientId());
								}else{
									sendMap.put("clientId","");
								}
								sendList.add(sendMap);
							}
						}
						List<Map<String,Object>> sendMsgResultList = asyncTask.sendMsg(map,sendList,1,1,otherMap);
						//将信息发送结果记录到数据库
						if(CollectionUtils.isNotEmpty(sendMsgResultList)){
							workOrderRepairDao.saveMsgOperation(sendMsgResultList);
						}
					}else{   //其他服务渠道和XCEC外出里程大于300或者DCEC外出里程大于90负责人都是区域服务经理
						// 用户在线报修时选择了服务站（工单状态为  待服务经理确认，则给服务经理发消息,区域服务经理已经在上面查出来了）
						List<Map<String,Object>> sendList = new ArrayList<>(AreaManagerMap);
						if(CollectionUtils.isEmpty(sendList)) {
							// TODO: 2019/7/18 不可达的逻辑，待验证删除-william
							// 未查询到要提醒的人群
							JSONObject jsb = new JSONObject();
							jsb.put("OrderId", map.get("OrderId"));
							jsb.put("OrderNo", OrderNo);
							ParameterTool.writeResponse(response,SMSEnum.type22.getIndex(),SMSEnum.type22.getName(),jsb);
							return null;
						}else {
							//准备发送信息
							/**
							 * sprint18: 【短信通知】【XCEC】短信通知取消
							 * 取消以下短信发送：
							 * 1）区域经理	新工单提醒	实时发送：您有新工单信息，工单号XXX，请查看。	- 当前
							 * 2）区域经理	新工单提醒（400指派给区域服务经理）实时发送：您有新工单信息，工单号XXX，请尽快处理。
							 * 3）区域经理	工单接受提醒	实时发送：您有工单被接受，工单号XXX，请查看。
							 * 4）区域经理	技师接单提醒	实时发送：您有工单被接单，工单号XXX，请查看。
							 * 5）区域经理	技师已出发提醒  实时发送：您的工单服务技师已出发，工单号XXX，请查看。
							 * 6）区域经理	技师开始维修提醒	实时发送：您的工单服务技师开始维修，工单号XXX，请查看。
							 * 7）区域经理	工单取消提醒	实时发送：您有工单取消，工单号XXX，请查看。
							 * 8）区域经理	服务商关闭工单提醒	实时发送：您有工单被关闭，工单号XXX，请查看。
 							 */
                            String serviceSubtype = MapUtils.getString(map, "ServiceSubtype", "");
                            String sellType = MapUtils.getString(map, "SellType", "");
                            // 服务站渠道
                            int OrderChannel = MapUtils.getIntValue(map, "OrderChannel");
							if (!"XCEC".equals(serviceChannel)){
								Map<String,Object> otherMap = new HashMap<String,Object>();
								String smsgbody = "您有新工单信息，工单号" + OrderNo + "，";
                                if(OrderChannel == 1){
                                    smsgbody = smsgbody + "属于\"" + sellType + "\"" + (StringUtils.isNotBlank(serviceSubtype) ? "-" + serviceSubtype : "") + "，";
                                }
                                smsgbody = smsgbody + "请尽快处理！";
								String stransmsg = "您有新工单信息，工单号" + OrderNo + "，";
                                if(OrderChannel == 1){
                                    stransmsg = stransmsg + "属于\"" + sellType + "\"" + (StringUtils.isNotBlank(serviceSubtype) ? "-" + serviceSubtype : "") + "，";
                                }
                                stransmsg = stransmsg + "请尽快处理！";
								otherMap.put("msgBody", smsgbody);//(,,,,)
								otherMap.put("msgTransMsg", stransmsg);
								otherMap.put("msgTitle", msgtitle);
								otherMap.put("function", msgFunctionNew);
								otherMap.put("category", msgCategoryNew);
								//开始发送消息(返回结果集为发送结果，要存入数据库，作为记录)
								List<Map<String,Object>> sendMsgResultList = asyncTask.sendMsg(map,sendList,1,1,otherMap);
								//将信息发送结果记录到数据库
								if(CollectionUtils.isNotEmpty(sendMsgResultList)){
									workOrderRepairDao.saveMsgOperation(sendMsgResultList);
								}
							}
						}
					}
				}
				//返回客户端，通知APP工单保存成功
				JSONObject jsb = new JSONObject();
				jsb.put("OrderId", map.get("OrderId"));
				jsb.put("OrderNo", OrderNo);
				ParameterTool.writeSuccessResponse(response, jsb);
				return null;
			}else {
				// 工单保存失败，返回客户端失败信息
				ParameterTool.writeErrorResponse(response);
				return null;
			}
		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			ParameterTool.writeErrorResponse(response);
		}
		return null;
	}

    private Long mergeEngineMsg(Map<String, Object> map, String serviceChannel) {
        String engineMsgId = MapUtils.getString(map, "EngineMsgId");
        if (serviceChannel.equals("CCI")) {
            String esn = MapUtils.getString(map, "ESN", "");
            EngineMsg engineMsg = engineMsgDao.getEngineMsgByESNString(esn);
            Map<String, Object> engineMsgMap = new HashMap<>();
            if (null == engineMsg) {
                engineMsgMap.put("ESN", MapUtils.getString(map, "ESN", ""));
                engineMsgMap.put("equipmentNo", MapUtils.getString(map, "VIN", ""));  //设备型号大部分有
                engineMsgMap.put("vehicleCompany", MapUtils.getString(map, "OEMName", ""));//车辆厂家可能有可能没有
                engineMsgMap.put("serviceChannel", serviceChannel);
                engineMsgMap.put("marketType", MapUtils.getString(map, "MarketType", ""));
                engineMsgMap.put("application", MapUtils.getString(map, "Application", ""));
                engineMsgMap.put("warrantyStartDate", MapUtils.getString(map, "WarrantyStartDate", ""));
                engineMsgDao.insertEngineMsg(engineMsgMap);  //保存发动机信息
                return MapUtils.getLong(engineMsgMap, "id");
            } else {
                engineMsgMap.put("ESN", MapUtils.getString(map, "ESN", ""));
                engineMsgMap.put("equipmentNo", MapUtils.getString(map, "VIN", ""));  //设备型号大部分有
                engineMsgMap.put("vehicleCompany", MapUtils.getString(map, "OEMName", ""));
                engineMsgMap.put("serviceChannel", serviceChannel);
                engineMsgMap.put("marketType", MapUtils.getString(map, "MarketType", ""));
                engineMsgMap.put("application", MapUtils.getString(map, "Application", ""));
                engineMsgMap.put("warrantyStartDate", MapUtils.getString(map, "WarrantyStartDate", ""));
                engineMsgMap.put("id", engineMsg.getId());
                engineMsgDao.updateByPrimaryKeySelective(engineMsgMap);
                return engineMsg.getId();
            }
        }
        Long id  = StringUtils.isNotBlank(engineMsgId) ? Long.valueOf(engineMsgId) : null;
        return id;
    }


    private class WorkOrderParameter {

        private String esn;
        // 服务子类型
        private String serviceSubtype;
        // 统修编号
        private String unifiedRepairNo;

        private List<String> serviceSubTypes;

        //健康检查类型
        private String healthExaminationCategory;

        public WorkOrderParameter(String esn, String serviceSubtype, String unifiedRepairNo,String healthExaminationCategory) {
            this.esn = esn;
            this.unifiedRepairNo = unifiedRepairNo;
            this.healthExaminationCategory = healthExaminationCategory;
            if (StringUtils.isNotBlank(serviceSubtype)) {
                this.serviceSubtype = serviceSubtype;
                // 服务子类型可以多选，前端传来的服务子类型是用;分隔的
                serviceSubTypes = Arrays.asList(serviceSubtype.split(";"));
            }
        }

        public String getEsn() {
            return esn;
        }

        public boolean containsServiceSubtype(String serviceSubtype) {
            return serviceSubTypes == null ? false : serviceSubTypes.contains(serviceSubtype);
        }

        public boolean isEmptyServiceSubtype() {
            return StringUtils.isBlank(this.serviceSubtype);
        }

        public String getUnifiedRepairNo() {
            return unifiedRepairNo;
        }

    }

    private static String errorMsg01 = "未选择服务子类型，24小时内不允许重复挂号";
    private static String errorMsg02 = "您当前的统修编号已挂单，不允许重复挂号";
    private static String errorMsg03 = "您的工单正在进行中，不允许重复挂号";

    private static String errorMsg04 = "您的工单正在进行中或已完成，不允许重复挂号";


    /**
     * 2.10.0 DBU增加服务工单校验
     * 目前不考虑并发的情况以及CRM同步的问题
     * 返回值说明：true允许创建工单，false不允许创建服务工单
     * <p>
     * 状态说明：
     * --|-------已完成工单状态------
     * |	14 服务完成
     * |	15 已取消
     * |	16 异常关闭
     * |	20 CAC已关闭
     * |	21 区域工程师异常关闭
     * |	22 CAC已取消
     * |
     * --|-------未完成工单状态-------
     * |	1  工单已创建
     * |	2  待服务经理确认
     * |	3  审核不通过
     * |	4  待服务商接单
     * |	6  待派服务技师
     * |	7  待服务技师接单
     * |	8  技师已接单
     * |	9  技师已拒单
     * |	10 已出发
     * |	11 已到达
     * |	12 维修中
     * |	13 待用户评价
     * |	17 待服务经理审核
     * |	18 待区域工程师处理
     * |	19 区域工程师已退回
     * |	31 异常关闭申请中
     * |
     * --|-------允许挂号的状态-------
     * |	15 已取消
     * |	16 异常关闭
     * |	20 CAC已关闭
     * |	22 CAC已取消
     * |   5  服务商已拒单
     * --|-----------------------------
     */
    private boolean validateWorkOrderFromDBU(WorkOrderParameter workOrderParameter, HttpServletResponse response) {
        // 第一步 校验当前服务工单是否选择了服务子类型
        if (workOrderParameter.isEmptyServiceSubtype()) {
            // 如果未选择服务子类型时，需要校验当前的esn 24小时重复挂单
            /**
             * 校验逻辑
             * 如果存在创建时间在24小时之内且工单状态为进行中或已完成的服务工单则不允许创建工单
             */
            // 1：获取最新的服务工单
            LatestWorkOrder latestWorkOrder = workOrderRepairDao.getLatestWorkOrderByEsn(workOrderParameter.getEsn());
            // 2：如果不存在服务工单 或 服务工单的创建时间已超过24小时 则可以挂单
            if (Objects.isNull(latestWorkOrder) || latestWorkOrder.isMoreThan24Hours()) {
                return true;
            }
            log.error(String.format("ESN:%s 不允许24小时之内重复挂号", workOrderParameter.getEsn()));
            ParameterTool.writeResponse(response, -200, errorMsg01);
            return false;
        }
        //如果服务子类型包含健康检查,且这个esn已经创建工单，不允许再次创建工单
        if (workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.HEALTH_EXAMINATION.getDesc())){
            List<String> subtypes = new ArrayList<>(4);
            subtypes.add(ServiceSubTypeEnum.HEALTH_EXAMINATION.getDesc());
            int	count = workOrderRepairDao.containsSubtypeByEsn(workOrderParameter.getEsn(),workOrderParameter.healthExaminationCategory,subtypes);
            if(count > 0) {
                log.error(String.format("ESN:%s 您的工单(服务子类型%s)正在进行中或已完成,不允许重复挂号", workOrderParameter.getEsn() ,subtypes));
                // 如果count大于0说明存在进行中或已完成的服务工单，则不可创建工单
                ParameterTool.writeResponse(response, -200, String.format(errorMsg04, subtypes));
                return false;
            }
        }

		// 第二步 校验当前服务工单是否选择了服务子类型 新机检查/首保
		if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.NEW_MACHINE_CHECK.getDesc()) ||
				workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.FIRST_UPKEEP.getDesc())) {
			/**
			 * 校验逻辑
			 * 如果存在进行中或已完成且服务子类型包含给定的子类型时(给定的子类型就是所传的子类型参数集合)，不允许再次创建工单
			 */
			List<String> subtypes = new ArrayList<>(4);
			if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.NEW_MACHINE_CHECK.getDesc())) {
				subtypes.add(ServiceSubTypeEnum.NEW_MACHINE_CHECK.getDesc());
			}
			if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.FIRST_UPKEEP.getDesc())) {
				subtypes.add(ServiceSubTypeEnum.FIRST_UPKEEP.getDesc());
			}

			int	count = workOrderRepairDao.containsGivenServiceSubtypeByEsn(workOrderParameter.getEsn(), subtypes);
			if(count > 0) {
				log.error(String.format("ESN:%s 您的工单(服务子类型%s)正在进行中或已完成,不允许重复挂号", workOrderParameter.getEsn() ,subtypes));
				// 如果count大于0说明存在进行中或已完成的服务工单，则不可创建工单
				ParameterTool.writeResponse(response, -200, String.format(errorMsg04, subtypes));
				return false;
			}
		}

		// 第三步 校验当前服务工单是否选择了统修
        //2023-10-25   开发campaign任务需求    去掉统修编号校验
		/*if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.UNIFIED_REPAIR.getDesc())) {
			*//**
			 * 校验逻辑
			 * 当一个ESN已经存在状态为进行中或已完成且统修编号为xxx的服务工单时，就不允许再次创建同一个ESN同一个统修编号的服务工单
			 * 总之：不允许出现ESN与统修编号相同的多个服务工单
			 *//*
			String unifiedRepairNo = workOrderParameter.getUnifiedRepairNo();
			int count = workOrderRepairDao.countSameUnifiedRepairNoByEsn(workOrderParameter.getEsn(), unifiedRepairNo);
			// 如果count大于0说明存在进行中或已完成且统修编号相同的服务工单，则不可创建工单
			if(count > 0) {
				log.error(String.format("ESN:%s 您的工单(服务子类型[统修])正在进行中或已完成,不允许重复挂号",workOrderParameter.getEsn()));
				ParameterTool.writeResponse(response, -200, errorMsg02);
				return false;
			}
		}*/

		// 第四步 校验当前服务工单是否选择了 保养/故障维修/BIS服务 服务子类型
		if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.UPKEEP_RECORD.getDesc()) ||
				workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.BIS_SERVICE.getDesc()) ||
				workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.INSTALLATION_SHIP_MACHINERY.getDesc()) ||
					workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.FAULT_HANDLING.getDesc()) ||
						workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.SUPPORT_TEST.getDesc()) ||
							workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.SECONDARY_MAINTENANCE.getDesc()) ||
								workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.HEALTH_EXAMINATION.getDesc())) {
			/**
			 * 校验逻辑
			 * 当存在服务子类型为保养/故障维修/BIS服务/支持测试且状态为进行中时，则不允许再次创建同服务子类型的服务工单
			 */
			List<String> subtypes = new ArrayList<>(5);
			if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.UPKEEP_RECORD.getDesc())) {
				subtypes.add(ServiceSubTypeEnum.UPKEEP_RECORD.getDesc());
			}
			if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.BIS_SERVICE.getDesc())) {
				subtypes.add(ServiceSubTypeEnum.BIS_SERVICE.getDesc());
			}
            if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.INSTALLATION_SHIP_MACHINERY.getDesc())) {
				subtypes.add(ServiceSubTypeEnum.INSTALLATION_SHIP_MACHINERY.getDesc());
			}
			if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.FAULT_HANDLING.getDesc())) {
				subtypes.add(ServiceSubTypeEnum.FAULT_HANDLING.getDesc());
			}
			if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.SUPPORT_TEST.getDesc())) {
				subtypes.add(ServiceSubTypeEnum.SUPPORT_TEST.getDesc());
			}

			if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.HEALTH_EXAMINATION.getDesc())) {
				subtypes.add(ServiceSubTypeEnum.HEALTH_EXAMINATION.getDesc());
			}

			if(workOrderParameter.containsServiceSubtype(ServiceSubTypeEnum.SECONDARY_MAINTENANCE.getDesc())) {
				subtypes.add(ServiceSubTypeEnum.SECONDARY_MAINTENANCE.getDesc());
			}


            int count = workOrderRepairDao.containsGivenServiceSubtypeByEsnWithing(workOrderParameter.getEsn(), subtypes);
            if (count > 0) {
                log.error(String.format("ESN:%s 您的工单(服务子类型%s)正在进行中,不允许重复挂号", workOrderParameter.getEsn(), subtypes));
                // 如果count大于0说明存在进行中的服务工单，则不可创建工单
                ParameterTool.writeResponse(response, -200, errorMsg03);
                return false;
            }
        }
        return true;
    }


    private enum ServiceSubTypeEnum {

        NEW_MACHINE_CHECK("新机检查"),
        FIRST_UPKEEP("首次保养"),

        UNIFIED_REPAIR("统修整改"),

		UPKEEP_RECORD("保养记录"),
		BIS_SERVICE("厂内服务"),// 厂内服务 已经删除   兼容老的app版本

        INSTALLATION_SHIP_MACHINERY("船机安装评审"),// 新增  船机安装评审
		FAULT_HANDLING("故障处理"),
		SUPPORT_TEST("支持测试"),
		SECONDARY_MAINTENANCE("二次保养"),
		HEALTH_EXAMINATION("健康检查")
		;

        private String desc;

        ServiceSubTypeEnum(String desc) {
            this.desc = desc;
        }

        public String getDesc() {
            return this.desc;
        }

    }


    /**
     * 服务站在线报修生成工单（通过APP）
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public ModelAndView serviceStationCreateWorkOrder(Map<String, Object> map) {
        HttpServletResponse response = (HttpServletResponse) map.get("response");
        try {
            String serviceChannel = MapUtils.getString(map, "OrderChannelName", ""); // 工单渠道
            int orderType = MapUtils.getIntValue(map, "OrderType", -1);//（xcec渠道：0:发动机维修 1:售时服务；DCEC渠道：2-发动机工单 3变速箱工单）
            String esn = MapUtils.getString(map, "ESN", "");
            String amtNo = MapUtils.getString(map, "AmtNo", "");
            // 2022-12-26 新增变速箱工单，该工单ESN可以为空
            if ((orderType == 3 && StringUtils.isEmpty(amtNo)) || (orderType != 3 && (StringUtils.isEmpty(esn) || StringUtils.isEmpty(serviceChannel) || ("XCEC".equals(serviceChannel) && orderType == -1)))) {
                ParameterTool.writeResponse(response, SMSEnum.type17.getIndex(), SMSEnum.type17.getName());
                return null;
            }
            // 2022-12-27 如果没有ESN的话，赋上''值
            if(orderType == 3){
                map.put("ESN", esn);
            }
            //2.10.0需求   对维修地址做长度限制   250个字
            String location = MapUtils.getString(map, "Location", "");
            if (location.length() > 250) {
                ParameterTool.writeResponse(response, SMSEnum.type605.getIndex(), SMSEnum.type605.getName());
                return null;
            }

            //没有smn从数据库获取
            if (!map.containsKey("SMN") || StringUtils.isEmpty(MapUtils.getString(map, "SMN", ""))) {
                Map<String, Object> engineMsg;
                if(serviceChannel.equals("DCEC")&&StringUtils.isNotBlank(amtNo)){
                    engineMsg = engineMsgDao.getSMNByAmtNo(amtNo);
                }else {
                    engineMsg = engineMsgDao.getSMNByESN(esn);
                }
               if(MapUtils.isNotEmpty(engineMsg)){
                    map.put("SMN",MapUtils.getString(engineMsg, "SMN", ""));
                }
            }

            //xcec售时工单需求
            //验证必填参数是否为空
            if ("XCEC".equals(serviceChannel) && orderType == 1) {
                //xcec售时工单判断字段是否为空
                if(map.containsKey("salesServiceType")&&"售前检查".equals(MapUtils.getString(map,"salesServiceType"))){//售前检查不校验起止日期
                    if (StringUtils.isEmpty(MapUtils.getString(map, "EnginePurpose", "")) ||
                            StringUtils.isEmpty(MapUtils.getString(map, "EngineSeries", "")) ||
                            StringUtils.isEmpty(MapUtils.getString(map, "ESN", "")) ||
                            StringUtils.isEmpty(MapUtils.getString(map, "OEMName", "")) ||
                            MapUtils.getIntValue(map, "IsOutside", -1) == -1 ||
                            StringUtils.isEmpty(MapUtils.getString(map, "ServiceStationId", ""))) {
                        ParameterTool.writeResponse(response, SMSEnum.type17.getIndex(), SMSEnum.type17.getName());
                        return null;
                    }
                }else{
                if (StringUtils.isEmpty(MapUtils.getString(map, "WarrantyStartDate", "")) ||
                        StringUtils.isEmpty(MapUtils.getString(map, "EnginePurpose", "")) ||
                        StringUtils.isEmpty(MapUtils.getString(map, "EngineSeries", "")) ||
                        StringUtils.isEmpty(MapUtils.getString(map, "ESN", "")) ||
                        StringUtils.isEmpty(MapUtils.getString(map, "OEMName", "")) ||
                        MapUtils.getIntValue(map, "IsOutside", -1) == -1 ||
                        StringUtils.isEmpty(MapUtils.getString(map, "ServiceStationId", ""))) {
                    ParameterTool.writeResponse(response, SMSEnum.type17.getIndex(), SMSEnum.type17.getName());
                    return null;
                }}
                //xcec服务站创建售时工单
                return serviceStationCreateWorkOrderXCECSale(map);
            }

            // 2.10.0 当DBU服务站选择服务子类型时是否能重复下单做校验
            // CCI就是DBU
            // 目前没考虑并发需要加锁的问题
            if ("CCI".equals(serviceChannel)) {
                // 开始校验服务工单
                if (!validateWorkOrderFromDBU(new WorkOrderParameter(esn, MapUtils.getString(map, "ServiceSubtype"), MapUtils.getString(map, "UnifiedRepairNo",""),MapUtils.getString(map, "HealthExaminationCategory")), response)) {
                    return null;
                }
                //【DBU工单】【安卓】【IOS】【BE】创建工单运行小时数/公里数判断  jira  22752
//                Map<String, Object> stringObjectMap = this.getAddFlag(map);
//                log.info("stringObjectMap:"+stringObjectMap.toString());
//                if (!MapUtils.getBoolean(stringObjectMap,"Flag",false)){
//                    ParameterTool.writeResponse(response,  SMSEnum.type700.getIndex(), MapUtils.getString(stringObjectMap,"MSG","请联系管理员，维护数据"));
//                    return null;
//                }

            }

            //ccec服务站报单
            if (serviceChannel.equals("CCEC")) {
                return serviceStationCreateWorkOrder4CCEC(map);
            }

            String procurementTime = "";  //采购日期
            //XCEC 所需的工单类型   故障地点省份和市

            String province = MapUtils.getString(map, "Province", "");
            String city = MapUtils.getString(map, "City", "");

            //通过用户手机号获取用户id
						long startTime = System.currentTimeMillis(); //获取开始时间
			List<UserT> customerList = loginDao.getUserByPhone(map.get("CustomerPhone").toString());
			long endTime = System.currentTimeMillis(); //获取结束时间
			System.out.println("程序运行时间：" + (endTime - startTime) + "ms"); //输出程序运行时间
			if (CollectionUtils.isNotEmpty(customerList)) {
                map.put("CustomerId", customerList.get(0).getId());  //往map中加入客户id字段对应的值
            }
            //处理用户Id
            UserT userT = UserThreadLocal.get();
            map.put("ProcessorId", userT.getId());
            map.put("ProcessorName", userT.getContact());

            //处理服务站Id
            String serviceStationId = AESTool.decryptString(MapUtils.getString(map, "ServiceStationId"));
            if (StringUtils.isEmpty(serviceStationId)) {
                ParameterTool.writeResponse(response, SMSEnum.type17.getIndex(), SMSEnum.type17.getName());
                return null;
            } else {
                map.put("ServiceStationId", serviceStationId);
            }

            //判断工单是否保存成功
            int saveResult = -1;
            // 查看报修发动机号当日是否已报修过，如果已经报修过，不可二次报修
            String ESN = MapUtils.getString(map, "ESN");
            // 2022-12-26 新增变速箱工单，该工单ESN可以为空，同样，变速箱当日不可二次报修
            String AmtNo = MapUtils.getString(map, "AmtNo");
            if ((StringUtils.isEmpty(ESN) && orderType != 3) || (orderType == 3 && StringUtils.isEmpty(AmtNo))) {
                ParameterTool.writeResponse(response, SMSEnum.type17.getIndex(), SMSEnum.type17.getName());
                return null;
            } else {
                String currentTime = LocalTimeUtil.getRealCurrentTime();
                currentTime = currentTime.substring(0, 10);
                map.put("currentTime", currentTime);
                // 根据发动机号，查询工单表当日是否存在此发动机报修信息
                // 2.10.0增加了更换了对DBU服务站报修的限制 CCI就是DBU
                if (!serviceChannel.equals("XCEC") && !serviceChannel.equals("CCI")) {  //XCEC同一个esn同一天没有限制报单次数
                    if(orderType == 3){   // 变速箱工单判断 变速箱号是否是当日第二次保修
                        int AmtNoCount = workOrderRepairDao.getAmtNoCount(map);
                        if (AmtNoCount > 0) {
                            ParameterTool.writeResponse(response, SMSEnum.type37.getIndex(), SMSEnum.type37.getName());
                            return null;
                        }
                    }else {
                        int ESNCount = workOrderRepairDao.getESNCount(map);
                        if (ESNCount > 0) {
                            ParameterTool.writeResponse(response, SMSEnum.type30.getIndex(), SMSEnum.type30.getName());
                            return null;
                        }
                    }
                } else {
                    //xcec增加校验 在APP系统是否存在未完成工单（工单状态!=服务完成、待用户评价、异常关闭、已取消、服务商已拒单）2.9.0运维需求
                    if (serviceChannel.equals("XCEC")) {
                        Map<String, Object> orderMsgMap = workOrderTDao.getOrderMsgByESN(4, Arrays.asList(14,13,16,15,5), ESN);
                        if (MapUtils.isNotEmpty(orderMsgMap)) {
                            String noFinishWorkOrderNo = MapUtils.getString(orderMsgMap, "workOrderNo", "");
                            if (StringUtils.isNotEmpty(noFinishWorkOrderNo)) {
                                ParameterTool.writeResponse(response, 30, "此ESN存在未完成工单，工单号:" + noFinishWorkOrderNo);
                                return null;
                            }
                        }
                    }
                }
            }

			// DCEC和XCEC查询工单审核人信息
			List<Map<String,Object>> areaManagerMap = new ArrayList<>();
			if("DCEC".equals(serviceChannel) || "XCEC".equals(serviceChannel)){
				long startTime1 = System.currentTimeMillis(); //获取开始时间
				areaManagerMap = workOrderRepairDao.getAreaManager(map);
				long endTime1 = System.currentTimeMillis(); //获取结束时间
				System.out.println("程序运行时间1：" + (endTime1 - startTime1) + "ms"); //输出程序运行时间
				if(CollectionUtils.isEmpty(areaManagerMap)) {
					//未查询到审核人，不能创建工单
					ParameterTool.writeResponse(response, SMSEnum.type23.getIndex(),SMSEnum.type23.getName());
					return null;
				}
			}

            Long engineMsgId = mergeEngineMsg(map, serviceChannel);
            map.put("EngineMsgId", engineMsgId);

            // 后台自动生成工单编号
            //String OrderNo = getOrderNo(map);
            /**
             * <p>
             *     自动生成工单编号，由 redis 更改为 sqlServer
             * </p>
             */
            String OrderNo = OrderGenerateUtil.getWorkOrderNo();
            map.put("OrderNo", OrderNo);
            //工单生成时间
            map.put("CreateTime", LocalTimeUtil.getRealCurrentTime());
            //工单创建人ID
            map.put("Creator", map.get("ProcessorId"));
            // 工单更新人
            map.put("Updator", map.get("ProcessorId"));
            // 工单更新时间（修改工单判断条件之一）
            map.put("UpdateTime", LocalTimeUtil.getRealCurrentTime());

            //用户保存插入工单成功返回的工单ID
            map.put("OrderId", "");

			// 判断是否需要外出（如果需要外出则故障点到服务站的距离要计算一下）
			Double distance = 0D;
			long startTime2 = System.currentTimeMillis(); //获取开始时间
			Map<String,Object> StationLatLon = workOrderRepairDao.getDistance(map);
			long endTime2 = System.currentTimeMillis(); //获取结束时间
			System.out.println("程序运行时间2：" + (endTime2 - startTime2) + "ms"); //输出程序运行时间
			if("1".equals(MapUtils.getString(map,"IsOutside"))) {
				//获取距离
				//服务站经纬度
				String stationLonLat = StationLatLon.get("PositionLon")+","+StationLatLon.get("PositionLat");
				String FaultLonLat = map.get("LocLon")+","+map.get("LocLat");
				try {
					distance = GetDistance.getDistance(stationLonLat, FaultLonLat);
					map.put("GuessDistance", distance);
				} catch (Exception e) {
					log.error(e.getMessage(),e);
					//返回客户
					ParameterTool.writeResponse(response,SMSEnum.type29.getIndex(),SMSEnum.type29.getName());
					return null;
				}
			}else{
				map.put("Location",MapUtils.getString(StationLatLon,"Address"));
				map.put("LocLat",MapUtils.getDouble(StationLatLon,"PositionLat"));
				map.put("LocLon",MapUtils.getDouble(StationLatLon,"PositionLon"));
				map.put("LocProvince",MapUtils.getString(StationLatLon,"Province"));
				map.put("LocCity",MapUtils.getString(StationLatLon,"City"));

			}

			if("CCI".equals(serviceChannel)){
				// DBU工单状态为 工单已创建
				map.put("OrderStatus", "1");
				//map.put("roleNo", "'R0074'");
			}else if("DCEC".equals(serviceChannel)){
				/**
				 * 修改 06-21 ：
				 * 由现有的单程超过90KM，需服务经理审批改为单程
				 * 超过50Km需要服务经理审批
				 */
				// 12月6号新需求，APP端审批权限及范围有变更，原外出里程大于90KM审批更改为100KM。所以由50改称100
				if("1".equals(MapUtils.getString(map,"IsOutside")) && distance >= 100D) {  //外出并且里程大于90
					map.put("OrderStatus", "2");
				}else{
					map.put("OrderStatus", "6");   //外出里程小于90   工单状态为代派服务技师
				}
			}else if("XCEC".equals(serviceChannel)){
				if("1".equals(MapUtils.getString(map,"IsOutside")) && distance >= 300D) {  //外出并且里程大于300
					map.put("OrderStatus", "2");
				}else{
					map.put("OrderStatus", "6");   //外出里程小于300   工单状态为代派服务技师
				}
				//当服务渠道是xcec，并且服务站创建工单外出时
				//后台保存出行类型(1火车   2飞机   3公交  4自驾)
				if("1".equals(MapUtils.getString(map,"IsOutside"))){
					int goOutType = MapUtils.getInteger(map,"GoOutType",4);
					map.put("GoOutType",goOutType);
				}
			} else {
				ParameterTool.writeResponse(response,SMSEnum.type18.getIndex(),SMSEnum.type18.getName());
				return null;
			}


			/**
			 * update 06-22
			 * 创建工单添加 索赔方式 和 急救方式 字段
			 */
			String natureClaim =  MapUtils.getString(map,"NatureClaim",null);
			String emergencyMode =  MapUtils.getString(map,"EmergencyMode",null);
			map.put("NatureClaim", natureClaim);
			map.put("EmergencyMode", emergencyMode);

            //根据高德获取地址
            String locLon = MapUtils.getString(map, "LocLon");
            String locLat = MapUtils.getString(map, "LocLat");
            if (StringUtils.isNotBlank(locLon) && StringUtils.isNotBlank(locLat) && MapUtils.getDouble(map, "LocLon") != 0 && MapUtils.getDouble(map, "LocLat") != 0) {
                Map<String, Object> reginInfo = null;
                if (MapUtils.getDouble(map, "LocLon") < 60) { // APP操作同步，非重传，参数需要座处理
                    reginInfo = GDRegion.getReginInfo(locLon,locLat);
                }else {
                    reginInfo = GDRegion.getReginInfo(locLat,locLon);
                }
                if (reginInfo!=null) {
                    if (StringUtils.isNotBlank(MapUtils.getString(reginInfo,"province"))) {
                        map.put("Province",reginInfo.get("province"));
                    }
                    if (StringUtils.isNotBlank(MapUtils.getString(reginInfo,"city"))) {
                        map.put("City",reginInfo.get("city"));
                    }
                    if (StringUtils.isNotBlank(MapUtils.getString(reginInfo,"location"))) {
                        map.put("Location",reginInfo.get("location"));
                    }
                }
            }
            //step1:保存工单信息
            saveResult = workOrderRepairDao.CreateWorkOrder(map);

			// DBU渠道
			if("CCI".equals(serviceChannel)){
				// 通过处理保修起始日（/转-）
				String warrantyStartDate = MapUtils.getString(map,"WarrantyStartDate");
				if(StringUtils.isNotEmpty(warrantyStartDate)){
					// 处理发动机信息表DBU无法处理的保修起始日数据
					if(warrantyStartDate.contains("/")){
						warrantyStartDate = warrantyStartDate.replace("/","-");
						map.put("WarrantyStartDate",warrantyStartDate);
					}
				}
				// 增加报修人信息
				map.put("directorName",userT.getContact());
				map.put("directorPhone",userT.getPhone());
			}
			//step2:同步至CRM接口
			Map<String,Object> tbMap = APP2CRM_WorkOrder_Convert(map,1,serviceChannel);

            tbMap.put("orderType",orderType);
			tbMap.put("city",city);
			tbMap.put("province",province);

			/**
			 * update 06-22
			 * 同步crm工单添加 索赔方式 和 急救方式 字段
			 */
			tbMap.put("natureClaim", natureClaim);
			tbMap.put("emergencyMode", emergencyMode);

			//xcec服务渠道  并且是外出，把是否外出标志和外出类型传给crm
			if("XCEC".equals(serviceChannel) && "1".equals(MapUtils.getString(map,"IsOutside"))){
				tbMap.put("vehicleType",MapUtils.getInteger(map,"GoOutType",4));
			}
			long startTime3 = System.currentTimeMillis(); //获取开始时间
			Map<String,Object> engineMsg = engineMsgDao.getSMNByESN(ESN);
			long endTime3 = System.currentTimeMillis(); //获取结束时间
			System.out.println("程序运行时间3：" + (endTime3 - startTime3) + "ms"); //输出程序运行时间
			if(MapUtils.isNotEmpty(engineMsg)){
                procurementTime = MapUtils.getString(engineMsg,"ShoppingDate","");
            }
            tbMap.put("procurementTime", procurementTime);
            if (map.containsKey("bookkeepingType")) {
                tbMap.put("BookkeepingType", map.get("bookkeepingType"));
            }
			long startTime4 = System.currentTimeMillis(); //获取开始时间
			//try {
			//将异步服务工单信息同步到crm的逻辑放到最后了

//			CRMResponeEntity CRMres = CRMApiUtils.getCRMServiceApi().syncAppOrderInfoToCRM(map.get("OrderChannelName").toString(), platformServiceDao, redisClientUtils, tbMap);
//                if (CRMres.getStatus() != 0) {
//                    // APP同步工单信息到CRM系统失败
//                    log.error("服务站APP在线报修同步工单信息至CRM失败，状态：" + CRMres.getStatus() + "，用户信息:" + CRMres.getMessage());
//                }
//            } catch (Exception e) {
//                //APP同步工单信息到CRM系统失败
//                log.error("服务站APP在线报修同步工单信息至CRM失败：" + e.getMessage(), e);
//            }
			long endTime4 = System.currentTimeMillis(); //获取结束时间
			System.out.println("程序运行时间4：" + (endTime4 - startTime4) + "ms"); //输出程序运行时间
			//判断工单是否保存成功
			long startTime5 = System.currentTimeMillis(); //获取开始时间
			if (saveResult > 0) {
                //记录用户行为日志（需要把上面保存成功的工单Id放进map中）
               //workOrderRepairDao.saveOperation(map);
				asyncTask.userActionRecord(map);
				if (MapUtils.getInteger(map, "OrderStatus") != 6) {  //如果工单状态是待派服务技师
                    //保存工单负责人信息
                    for (Map<String, Object> amap : areaManagerMap) {
                        map.put("PrincipalId", amap.get("ID"));
                        map.put("IsPrincipal", 1);
                        //workOrderRepairDao.savePrincipal(map);
						asyncTask.saveOrderPrincipal(map);
					}
                }

				// DCEC订单发送通知给相关人员
				if("DCEC".equals(serviceChannel) || "XCEC".equals(serviceChannel)){
					if(MapUtils.getInteger(map,"OrderStatus") != 6) {  //如果工单状态是待派服务技师
						/**
						 * 20210812 【短信通知】【XCEC】短信通知取消
						 * 取消以下短信发送：
						 * 1）区域经理	新工单提醒	实时发送：您有新工单信息，工单号XXX，请查看。
						 * 2）区域经理	新工单提醒（400指派给区域服务经理）实时发送：您有新工单信息，工单号XXX，请尽快处理。- 当前
						 * 3）区域经理	工单接受提醒	实时发送：您有工单被接受，工单号XXX，请查看。
						 * 4）区域经理	技师接单提醒	实时发送：您有工单被接单，工单号XXX，请查看。
						 * 5）区域经理	技师已出发提醒  实时发送：您的工单服务技师已出发，工单号XXX，请查看。
						 * 6）区域经理	技师开始维修提醒	实时发送：您的工单服务技师开始维修，工单号XXX，请查看。
						 * 7）区域经理	工单取消提醒	实时发送：您有工单取消，工单号XXX，请查看。
						 * 8）区域经理	服务商关闭工单提醒	实时发送：您有工单被关闭，工单号XXX，请查看。
						 */
						if (!"XCEC".equals(serviceChannel)){
							// 工单状态待区域服务经理确认，发送消息
							List<Map<String,Object>> sendList = new ArrayList<>(areaManagerMap);
							//准备发送信息
							Map<String,Object> otherMap = new HashMap<String,Object>();
							String smsgbody = msgbody;
							smsgbody = smsgbody.replace("***", OrderNo);
							String stransmsg = transmsg;
							stransmsg = stransmsg.replace("***", OrderNo);
							otherMap.put("msgBody", smsgbody);//(,,,,)
							otherMap.put("msgTransMsg", stransmsg);
							otherMap.put("msgTitle", msgtitle);
							otherMap.put("function", msgFunctionNew);
							otherMap.put("category", msgCategoryNew);
                            asyncTask.newSendMsg(map,sendList,1,1,otherMap);
						} else {
							if (CollectionUtils.isNotEmpty(areaManagerMap) && StringUtils.isNotEmpty(serviceStationId)) {
								/**
								 * sprint18: 【短信通知】【XCEC】区域经理接收国六故障提醒
								 * 区域经理接收国六故障提醒短信，
								 * ①短信模板：国六故障提醒：XXX服务商，工单号xxx,发动机序列XXX，现有国六服务审批请尽快处理
								 * ②发送机制：工单提交时判断“发动机序列”为X12和M15系列,视为国6机型，则实时发送提醒短信；判断发动机序列条件项支持后台扩展，例如现在判断X12、15N，后续陆续会增加或删除新的发动机序列。
								 */
								//查询白名单中的type值为2的；  2为国六的机型
								// 区域经理列表
								ServiceStationT serviceStationT = serviceStationDao.getSSById(Long.valueOf(serviceStationId));
								List<Map<String, Object>> sendList = new ArrayList<>(areaManagerMap);
								List<WhiteListT> whiteListTList = whiteListTDao.getListByType(2);
								String engineType = MapUtil.getMapValue(map, "engineType");
								if (CollectionUtils.isNotEmpty(whiteListTList) && StringUtils.isNotEmpty(engineType)) {
									List<String> contentList = whiteListTList.stream().filter(e -> engineType.contains(e.getContent())).map(WhiteListT::getContent).collect(Collectors.toList());
									if (CollectionUtils.isNotEmpty(contentList)) {
										String format = String.format(xcecGuoLiuStr, serviceStationT.getStationname(), OrderNo, esn);
										//准备发送信息
										Map<String, Object> otherMap = new HashMap<String, Object>();
										otherMap.put("msgBody", format);
										otherMap.put("msgTransMsg", format);
										otherMap.put("msgTitle", msgtitle);
										otherMap.put("function", msgFunctionNew);
										otherMap.put("category", msgCategoryNew);

                                        asyncTask.newSendMsg(map,sendList,1,0,otherMap);
									}
								}
								// sprint18-【短信通知】【XCEC】短信通知修改
								//  2）现状：区域经理接收外出审批单提醒：服务站、用户和CAC创建外出工单成功且外出里程大于等于300公里（服务商位置和用户故障位置系统推荐最短里程）每10分钟发送一次提醒短信：您有未审批工单，工单号XXX，请尽快审批。三十分钟自动审核通过。
								//   ---修改：①发送机制修改：创建当时实时发一次，第10分钟发一次，第20分钟发一次，第30分钟自动审批通过，共发三条短信。
								//   		②短信模板修改：外出审批提醒：XX服务商，工单号xx，外出里程xxkm，请尽快审批。
								if ("1".equals(MapUtils.getString(map,"IsOutside")) && distance > 300D) {
									String xcecOutApplyStr = String.format(xcecOverTimeBody, serviceStationT.getStationname(), OrderNo, distance);
									//准备发送信息
									Map<String, Object> otherMap = new HashMap<String, Object>();
									otherMap.put("msgBody", xcecOutApplyStr);
									otherMap.put("msgTransMsg", xcecOutApplyStr);
									otherMap.put("msgTitle", xcecGuoLiuTitle);
									otherMap.put("function", msgFunctionNew);
									otherMap.put("category", msgCategoryNew);
                                    asyncTask.newSendMsg(map,sendList,1,0,otherMap);
								}
							}
						}
					}
				}
                //是否包含芯管家的标识 包含的话同步标识
                if (map.containsKey("xgjRecordId") && map.containsKey("xgjESN")) {
                    Long xgjRecordId = MapUtils.getLong(map, "xgjRecordId");
                    String xgjESN = MapUtils.getString(map, "xgjESN");
                    String workOrderESN = MapUtils.getString(map, "ESN");
                    if (null != xgjRecordId && StringUtils.isNotEmpty(workOrderESN)) {
                        String url = String.format(xgjUrl + XgjApiConst.XGJ_URL_RECORD);
                        Map<String,Object> xgjMap = new HashMap<>();
                        xgjMap.put("order_no",map.get("OrderNo"));
                        xgjMap.put("esn",workOrderESN);
                        xgjMap.put("record_id",xgjRecordId);
                        xgjMap.put("user_id",userT.getId());
                        XGJBasicResponse xgjBasicResponse = doPut(url, JSONObject.fromObject(xgjMap).toString(), XGJBasicResponse.class);
                    }
                }

				long endTime5 = System.currentTimeMillis(); //获取结束时间
				System.out.println("程序运行时间5：" + (endTime5 - startTime5) + "ms"); //输出程序运行时间

                // 异步处理请求   将服务工单信息同步到crm
                //sprint45 挂号失败的情况下需要给创建人推短信    这里将创建人信息放进去
                tbMap.put("Creator",userT.getId());
                tbMap.put("UserPhone",userT.getPhone());
                tbMap.put("UserName",userT.getUserName());
                ThreadTask synThread = new ThreadTask(map, platformServiceDao, redisClientUtils, tbMap);
                ThreadPoolUtil.newTask(synThread);

				//返回客户端通知工单保存成功
				JSONObject jsb = new JSONObject();
				jsb.put("OrderId", map.get("OrderId"));
				jsb.put("OrderNo", OrderNo);
				ParameterTool.writeSuccessResponse(response, jsb);
				return null;
			}else {
				//工单信息保存失败
				ParameterTool.writeResponse(response, SMSEnum.type99.getIndex(),SMSEnum.type99.getName());
				return null;
			}
		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
			ParameterTool.writeErrorResponse(response);
			//主动回滚事务
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
		return null;
	}

    private <T> T doPut(String url, String jsonString, Class<T> responseType) {
        Header wwidHeader = new BasicHeader("wwid", wwid);
        Header tokenHeader = new BasicHeader("token", token);
        log.error("芯管家同步故障码对应的工单： "+ url+"  参数：" + jsonString+"   token:" +token +"  wwid:"+ wwid);
        String response = HttpUtils.postJson(url,jsonString, new ResponseHandler<String>() {
            @Override
            public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
                if (response.getStatusLine().getStatusCode() == 200
                        || response.getStatusLine().getStatusCode() == 206) {
                    HttpEntity httpEntity = response.getEntity();
                    return EntityUtils.toString(httpEntity);
                } else {
                    log.error("芯管家同步故障码对应的工单失败： 返回结果"+response);
                    /*LogUtils.error(Log.ERROR_LOGGER, "芯管家-变更接口：" + url
                            + "；返回结果：" + response);*/
                }
                return null;
            }
        }, tokenHeader);
        log.error("芯管家同步故障码对应的工单返回结果："+ response);
        //LogUtils.info(Log.INFO_LOGGER, "芯管家-变更接口，返回数据：" + response);
        if (org.apache.commons.lang.StringUtils.isNotEmpty(response)) {
            return JsonUtils.toJavaObject(response, responseType);
        }
        return null;
    }
    // dbu创建工单验证 是否可以添加
    public Map<String,Object> getAddFlag(Map<String, Object> map){
        //type  1 WorkHours  2 WorkMileages
        String esn = MapUtils.getString(map, "ESN", "");
        String uploadTime = MapUtils.getString(map, "UploadTime", "");
        String workMileages = MapUtils.getString(map, "WorkMileages", "");
        String workHours = MapUtils.getString(map, "WorkHours", "");
        // 是否可填
        boolean numFlag = true;
        String msgStr = "";
        List<WorkOrderT> orderTList = workOrderTDao.getListByESNAndChannel(esn, 1L);
        log.info("stringObjectMap:orderTList:"+(CollectionUtils.isNotEmpty(orderTList)?orderTList.toString():"未获取数据"));
        if (CollectionUtils.isNotEmpty(orderTList)) {
            orderTList = orderTList.stream().filter(e -> StringUtils.isNotBlank(e.getUploadTime())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(orderTList)) {
                orderTList.sort(Comparator.comparing(WorkOrderT::getUploadTime));
                if(StringUtils.isNotBlank(workHours)){
                    //获取包含 小时数的工单集合
                    List<WorkOrderT> workHoursOrderList = orderTList.stream().filter(e -> StringUtils.isNotBlank(e.getWorkHours())).collect(Collectors.toList());
                    log.info("stringObjectMap:workHoursOrderList:"+(CollectionUtils.isNotEmpty(workHoursOrderList)?workHoursOrderList.toString():"未获取数据"));
                    log.info("stringObjectMap:workHoursOrderList:"+ workHoursOrderList.size());
                    if (CollectionUtils.isNotEmpty(workHoursOrderList)) {
                        if (workHoursOrderList.size()==1) {
                            WorkOrderT workOrderTStart = workHoursOrderList.get(0);
                            log.info("stringObjectMap:workOrderTStart---1:"+ workOrderTStart.toString()+"------uploadTime"+uploadTime);
                            if (LocalTimeUtil.isBefore(uploadTime,workOrderTStart.getUploadTime())) {
                                numFlag = this.pramToDouble(workHours)<this.pramToDouble(workOrderTStart.getWorkHours());
                                if(!numFlag){
                                    msgStr = "输入的值应小于"+this.pramToDouble(workOrderTStart.getWorkHours())+"小时";
                                }
                            }else {
                                numFlag = this.pramToDouble(workHours)>this.pramToDouble(workOrderTStart.getWorkHours());
                                if(!numFlag){
                                    msgStr = "输入的值应大于"+this.pramToDouble(workOrderTStart.getWorkHours())+"小时";
                                }
                            }
                            log.info("stringObjectMap:workOrderTStart---1:msgStr:"+msgStr);
                        }else {
                            WorkOrderT workOrderTStart = workHoursOrderList.get(0);
                            log.info("stringObjectMap:workOrderTStart---2::"+workOrderTStart.toString());
                            WorkOrderT workOrderTEnd = workHoursOrderList.get(workHoursOrderList.size()-1);
                            log.info("stringObjectMap:workOrderTEnd---2::"+workOrderTEnd.toString());
                            if(LocalTimeUtil.isBefore(uploadTime,workOrderTStart.getUploadTime())) {
                                numFlag = this.pramToDouble(workHours)<this.pramToDouble(workOrderTStart.getWorkHours());
                                if(!numFlag){
                                    msgStr = "输入的值应小于"+this.pramToDouble(workOrderTStart.getWorkHours())+"小时";
                                }
                                log.info("stringObjectMap:workOrderTEnd---2---1:msgStr:"+msgStr);
                            }else if(LocalTimeUtil.isBefore(workOrderTEnd.getUploadTime(),uploadTime)){
                                numFlag = this.pramToDouble(workHours)>this.pramToDouble(workOrderTEnd.getWorkHours());
                                if(!numFlag){
                                    msgStr = "输入的值应大于"+this.pramToDouble(workOrderTEnd.getWorkHours())+"小时";
                                }
                                log.info("stringObjectMap:workOrderTEnd---2---2:msgStr:"+msgStr);
                            }else {
                                WorkOrderT lastWorkOrder = this.getLastWorkOrder(workHoursOrderList, uploadTime);
                                log.info("stringObjectMap:lastWorkOrder---2---3:lastWorkOrder:"+lastWorkOrder.toString());
                                WorkOrderT beforWorkOrder = this.getbeforWorkOrder(workHoursOrderList, uploadTime);
                                log.info("stringObjectMap:beforWorkOrder---2---3:beforWorkOrder:"+beforWorkOrder.toString());
                                //正常情况 都不为空
                                if (this.pramToDouble(beforWorkOrder.getWorkHours())>=this.pramToDouble(lastWorkOrder.getWorkHours())) {
                                    numFlag = false;
                                    msgStr = "请联系400报单";
                                }else {
                                    if (this.pramToDouble(beforWorkOrder.getWorkHours())<this.pramToDouble(workHours)&&
                                            this.pramToDouble(workHours)<this.pramToDouble(lastWorkOrder.getWorkHours())) {
                                        numFlag = true;
                                    }else {
                                        numFlag = false;
                                        msgStr = "输入的值应大于"+this.pramToDouble(beforWorkOrder.getWorkHours())+"小时且小于"+this.pramToDouble(workOrderTEnd.getWorkHours())+"小时";
                                    }
                                }
                                log.info("stringObjectMap:beforWorkOrder---2---3:msgStr:"+msgStr);
                            }
                        }
                    }else {
                        numFlag =true;
                    }
                }else if(StringUtils.isNotBlank(workMileages)){
                    //获取包含 公里数的工单集合
                    List<WorkOrderT> workMileagesOrderList = orderTList.stream().filter(e -> StringUtils.isNotBlank(e.getWorkMileages())).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(workMileagesOrderList)) {
                        log.info("stringObjectMap:workMileagesOrderList---2:"+workMileagesOrderList.toString());
                        if (workMileagesOrderList.size()==1) {
                            WorkOrderT workOrderTStart = workMileagesOrderList.get(0);
                            log.info("stringObjectMap:workOrderTStart---2:"+workOrderTStart.toString());
                            if (LocalTimeUtil.isBefore(uploadTime,workOrderTStart.getUploadTime())) {
                                numFlag = this.pramToDouble(workMileages)<this.pramToDouble(workOrderTStart.getWorkMileages());
                                if(!numFlag){
                                    msgStr = "输入的值应小于"+this.pramToDouble(workOrderTStart.getWorkMileages())+"公里";
                                }
                            }else {
                                numFlag = this.pramToDouble(workMileages)>this.pramToDouble(workOrderTStart.getWorkMileages());
                                if(!numFlag){
                                    msgStr = "输入的值应大于"+this.pramToDouble(workOrderTStart.getWorkMileages())+"公里";
                                }
                            }
                            log.info("stringObjectMap:workOrderTStart---2-msgStr:"+msgStr.toString());
                        }else {
                            WorkOrderT workOrderTStart = workMileagesOrderList.get(0);
                            log.info("stringObjectMap:workOrderTStart---2:"+workOrderTStart.toString());
                            WorkOrderT workOrderTEnd = workMileagesOrderList.get(workMileagesOrderList.size()-1);
                            log.info("stringObjectMap:workOrderTEnd---2:"+workOrderTEnd.toString());
                            if(LocalTimeUtil.isBefore(uploadTime,workOrderTStart.getUploadTime())) {
                                numFlag = this.pramToDouble(workMileages)<this.pramToDouble(workOrderTStart.getWorkMileages());
                                if(!numFlag){
                                    msgStr = "输入的值应小于"+this.pramToDouble(workOrderTStart.getWorkMileages())+"公里";
                                }
                                log.info("stringObjectMap:workOrderTEnd--msgStr-2:"+msgStr.toString());
                            }else if(LocalTimeUtil.isBefore(workOrderTEnd.getUploadTime(),uploadTime)){
                                numFlag = this.pramToDouble(workMileages)>this.pramToDouble(workOrderTEnd.getWorkMileages());
                                if(!numFlag){
                                    msgStr = "输入的值应大于"+this.pramToDouble(workOrderTEnd.getWorkMileages())+"公里";
                                }
                                log.info("stringObjectMap:workOrderTEnd--msgStr-2:"+msgStr.toString());
                            }else {
                                WorkOrderT lastWorkOrder = this.getLastWorkOrder(workMileagesOrderList, uploadTime);
                                log.info("stringObjectMap:lastWorkOrder--2:"+lastWorkOrder.toString());
                                WorkOrderT beforWorkOrder = this.getbeforWorkOrder(workMileagesOrderList, uploadTime);
                                log.info("stringObjectMap:beforWorkOrder--2:"+beforWorkOrder.toString());
                                //正常情况 都不为空
                                if (this.pramToDouble(beforWorkOrder.getWorkMileages())>=this.pramToDouble(lastWorkOrder.getWorkMileages())) {
                                    numFlag = false;
                                    msgStr = "请联系400报单";
                                    log.info("stringObjectMap:beforWorkOrder--2----msgStr:"+msgStr.toString());
                                }else {
                                    if (this.pramToDouble(beforWorkOrder.getWorkMileages())<this.pramToDouble(workMileages)&&
                                            this.pramToDouble(workMileages)<this.pramToDouble(lastWorkOrder.getWorkMileages())) {
                                        numFlag = true;
                                    }else {
                                        numFlag = false;
                                        msgStr = "输入的值应大于"+this.pramToDouble(beforWorkOrder.getWorkMileages())+"公里且小于"+this.pramToDouble(workOrderTEnd.getWorkMileages())+"公里";
                                    }
                                    log.info("stringObjectMap:beforWorkOrder--2----msgStr:"+msgStr.toString());
                                }
                            }
                        }
                    }else {
                        numFlag =true;
                    }
                }
            }
        }
        Map<String,Object> mapVo = new HashMap<>();
        mapVo.put("Flag",numFlag);
        mapVo.put("MSG",msgStr);
        return mapVo;
    }

    public double pramToDouble(String prams){
        if (StringUtils.isNotBlank(prams)) {
            return Double.valueOf(prams);
        }
        return 0;
    }

    public WorkOrderT getLastWorkOrder(List<WorkOrderT> orderTList,String uploadTime){
        // //type  1 WorkHours  2 WorkMileages
        for (WorkOrderT workOrderT : orderTList) {
            if (LocalTimeUtil.isBefore(uploadTime, workOrderT.getUploadTime())) {
                return workOrderT;
            }
        }
        return null;
    }

    public WorkOrderT getbeforWorkOrder(List<WorkOrderT> orderTList,String uploadTime){
        // //type  1 WorkHours  2 WorkMileages
        WorkOrderT workOrderTBefor = new WorkOrderT();
        for (WorkOrderT workOrderT : orderTList) {
            if (LocalTimeUtil.isBefore(uploadTime, workOrderT.getUploadTime())) {
               break;
            }
            workOrderTBefor = workOrderT;
        }
        return workOrderTBefor;
    }

    //ccec服务站创建工单
    @Transactional
    public ModelAndView serviceStationCreateWorkOrder4CCEC(Map<String, Object> map) {
        HttpServletResponse response = (HttpServletResponse) map.get("response");

        //验证必填参数是否为空
        if (!chechParameters(map)) {
            ParameterTool.writeResponse(response, SMSEnum.type17.getIndex(), SMSEnum.type17.getName());
            return null;
        }
        //处理发动机信息--已确认不需维护

        //整理工单信息
        //通过用户手机号获取用户id
        List<UserT> customerList = loginDao.getUserByPhone(map.get("CustomerPhone").toString());
        if (CollectionUtils.isNotEmpty(customerList)) {
            map.put("CustomerId", customerList.get(0).getId());  //往map中加入客户id字段对应的值
        }

        //处理服务站Id
        String serviceStationId = AESTool.decryptString(MapUtils.getString(map, "ServiceStationId"));
        map.put("ServiceStationId", serviceStationId);

        // 检查该服务站是否有400审核人
        List<Map<String, Object>> areaManagerMap = workOrderRepairDao.getAreaManager(map);
        if (CollectionUtils.isEmpty(areaManagerMap)) {
            //未查询到审核人，不能创建工单
            ParameterTool.writeResponse(response, SMSEnum.type23.getIndex(), SMSEnum.type23.getName());
            return null;
        }

        UserT userT = UserThreadLocal.get();
        map.put("ProcessorId", userT.getId());
        map.put("ProcessorName", userT.getContact());

        //判断工单是否保存成功
        int saveResult = -1;
        // 查看报修发动机号当日是否已报修过，如果已经报修过，不可二次报修
        String ESN = MapUtils.getString(map, "ESN");
        String currentTime = LocalTimeUtil.getRealCurrentTime();
        currentTime = currentTime.substring(0, 10);

        // 后台自动生成工单编号
        //String OrderNo = getOrderNo(map);
        /**
         * <p>
         *     自动生成工单编号，由 redis 更改为 sqlServer
         * </p>
         */
        String OrderNo = OrderGenerateUtil.getWorkOrderNo();
        map.put("OrderNo", OrderNo);
        //工单生成时间
        map.put("CreateTime", LocalTimeUtil.getRealCurrentTime());
        //工单创建人ID
        map.put("Creator", map.get("ProcessorId"));
        // 工单更新人
        map.put("Updator", map.get("ProcessorId"));
        // 工单更新时间（修改工单判断条件之一）
        map.put("UpdateTime", LocalTimeUtil.getRealCurrentTime());

        //用户保存插入工单成功返回的工单ID
        map.put("OrderId", "");

        map.put("CustomerCompanyName", MapUtils.getString(map, "CustomerCompany"));

        // 判断是否需要外出（如果需要外出则故障点到服务站的距离要计算一下）
        Double distance = 0D;
        Map<String, Object> StationLatLon = workOrderRepairDao.getDistance(map);
        if ("1".equals(MapUtils.getString(map, "IsOutside"))) {
            //获取距离
            //服务站经纬度
            String stationLonLat = StationLatLon.get("PositionLon") + "," + StationLatLon.get("PositionLat");
            String FaultLonLat = map.get("LocLon") + "," + map.get("LocLat");
            try {
                distance = GetDistance.getDistance(stationLonLat, FaultLonLat);
                map.put("GuessDistance", distance);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                //返回客户
                ParameterTool.writeResponse(response, SMSEnum.type29.getIndex(), SMSEnum.type29.getName());
                return null;
            }
        } else {
            map.put("Location", MapUtils.getString(StationLatLon, "Address"));
            map.put("LocLat", MapUtils.getDouble(StationLatLon, "PositionLat"));
            map.put("LocLon", MapUtils.getDouble(StationLatLon, "PositionLon"));
            map.put("LocProvince", MapUtils.getString(StationLatLon, "Province"));
            map.put("LocCity", MapUtils.getString(StationLatLon, "City"));
        }

        //标记工单状态
        int requireType = MapUtils.getIntValue(map, "RequestType");
        if (1 == requireType) {
            // 保内需求 待400审核
            map.put("OrderStatus", "23");
        } else {
            // 非保内需求 待派服务技师
            map.put("OrderStatus", "6");
        }

        //step1:保存工单信息
        saveResult = workOrderRepairDao.CreateWorkOrder(map);

        //2.4.0 ccec服务站创建工单   需要更新发动机基础数据表的是否起保和预计起保日期
        Map<String, Object> updateEnginMap = new HashMap<>();
        updateEnginMap.put("ESN", MapUtils.getString(map, "ESN"));
        updateEnginMap.put("isWarrantyStart", MapUtils.getIntValue(map, "IsInsured"));
        if (StringUtils.isNotEmpty(MapUtils.getString(map, "EstimateWarrantyStartDate", ""))) {
            updateEnginMap.put("estimateWarrantyStartDate", MapUtils.getString(map, "EstimateWarrantyStartDate", ""));
        }
        int updateCount = engineMsgDao.updateMsgByEsn(updateEnginMap);

        //step2:同步至CRM接口
        Map<String, Object> tbMap = APP2CRM_WorkOrder_Convert(map, 1, "CCEC");
        tbMap.put("customerName", userT.getContact());
        tbMap.put("customerPhone", userT.getPhone());
        tbMap.put("isInsteadRepairs", -1);
        String OrderNoCRM = "";
        try {
            CRMResponeEntity CRMres = CRMApiUtils.getCRMServiceApi().syncAppOrderInfoToCRM(map.get("OrderChannelName").toString(), platformServiceDao, redisClientUtils, tbMap,null);
            if (CRMres.getStatus() != 0) {
                // APP同步工单信息到CRM系统失败
                log.error("服务站APP在线报修同步工单信息至CRM失败，状态：" + CRMres.getStatus() + "，用户信息:" + CRMres.getMessage());
            } else {
                if (CRMres.getData().containsKey("CCSSOrderNo")) {
                    OrderNoCRM = CRMres.getData().getString("CCSSOrderNo");
                }
            }
        } catch (Exception e) {
            //APP同步工单信息到CRM系统失败
            log.error("服务站APP在线报修同步工单信息至CRM失败：" + e.getMessage(), e);
        }

        //判断工单是否保存成功
        if (saveResult > 0) {
            //记录用户行为日志（需要把上面保存成功的工单Id放进map中）
            workOrderRepairDao.saveOperation(map);
            if (MapUtils.getInteger(map, "OrderStatus") != 6) {  //如果工单状态是待派服务技师
                //保存工单负责人信息
                for (Map<String, Object> amap : areaManagerMap) {
                    map.put("PrincipalId", amap.get("ID"));
                    map.put("IsPrincipal", 1);
                    workOrderRepairDao.savePrincipal(map);
                }

                //推送消息
                // 工单状态待区域服务经理确认，发送消息
                List<Map<String, Object>> sendList = new ArrayList<>(areaManagerMap);
                //准备发送信息
                Map<String, Object> otherMap = new HashMap<String, Object>();
                String smsgbody = msgbodyCCEC;
                String stransmsg = transmsgCCEC;
                String msg = "";
                if (StringUtils.isNotEmpty(OrderNoCRM)) {
                    msg = OrderNo + "（FW号" + OrderNoCRM + "）";
                    smsgbody = String.format(smsgbody, msg);
                    stransmsg = String.format(stransmsg, msg);
                } else {
                    smsgbody = String.format(smsgbody, OrderNo);
                    stransmsg = String.format(stransmsg, OrderNo);
                }
                otherMap.put("msgBody", smsgbody);
                otherMap.put("msgTransMsg", stransmsg);
                otherMap.put("msgTitle", msgtitle);
                otherMap.put("function", msgFunctionNew);
                otherMap.put("category", msgCategoryNew);
                //开始发送消息(返回结果集为发送结果，要存入数据库，作为记录)
                List<Map<String, Object>> sendMsgResultList = asyncTask.sendMsg(map, sendList, 1, 1, otherMap);
                //将信息发送结果记录到数据库
                if (CollectionUtils.isNotEmpty(sendMsgResultList)) {
                    workOrderRepairDao.saveMsgOperation(sendMsgResultList);
                }
            }

            //返回客户端通知工单保存成功
            JSONObject jsb = new JSONObject();
            jsb.put("OrderId", map.get("OrderId"));
            jsb.put("OrderNo", OrderNo);
            ParameterTool.writeSuccessResponse(response, jsb);
            return null;
        } else {
            //工单信息保存失败
            ParameterTool.writeResponse(response, SMSEnum.type99.getIndex(), SMSEnum.type99.getName());
            return null;
        }
    }


    //xcec服务站创建售时工单
    @Transactional
    public ModelAndView serviceStationCreateWorkOrderXCECSale(Map<String, Object> map) {
        WorkOrderSynchroT workOrderSynchro = new WorkOrderSynchroT();
        HttpServletResponse response = (HttpServletResponse) map.get("response");
        //通过用户手机号获取用户id
        List<UserT> customerList = loginDao.getUserByPhone(map.get("CustomerPhone").toString());
        if (CollectionUtils.isNotEmpty(customerList)) {
            map.put("CustomerId", customerList.get(0).getId());  //往map中加入客户id字段对应的值
        }

        //处理服务站Id
        String serviceStationId = AESTool.decryptString(MapUtils.getString(map, "ServiceStationId"));
        map.put("ServiceStationId", serviceStationId);

        // 检查该服务站是否有区域服务经理审核人
        List<Map<String, Object>> areaManagerMap = workOrderRepairDao.getAreaManager(map);
        if (CollectionUtils.isEmpty(areaManagerMap)) {
            //未查询到审核人，不能创建工单
            ParameterTool.writeResponse(response, SMSEnum.type23.getIndex(), SMSEnum.type23.getName());
            return null;
        }

        UserT userT = UserThreadLocal.get();
        map.put("ProcessorId", userT.getId());
        map.put("ProcessorName", userT.getContact());

        //判断工单是否保存成功
        int saveResult = -1;

        // 后台自动生成工单编号
        //String OrderNo = getOrderNo(map);
        /**
         * <p>
         *     自动生成工单编号，由 redis 更改为 sqlServer
         * </p>
         */
        String OrderNo = OrderGenerateUtil.getWorkOrderNo();
        map.put("OrderNo", OrderNo);
        //工单生成时间
        map.put("CreateTime", LocalTimeUtil.getRealCurrentTime());
        //工单创建人ID
        map.put("Creator", map.get("ProcessorId"));
        // 工单更新人
        map.put("Updator", map.get("ProcessorId"));
        // 工单更新时间（修改工单判断条件之一）
        map.put("UpdateTime", LocalTimeUtil.getRealCurrentTime());

        //用户保存插入工单成功返回的工单ID
        map.put("OrderId", "");

        // 判断是否需要外出（如果需要外出则故障点到服务站的距离要计算一下）
        Double distance = 0D;
        Map<String, Object> StationLatLon = workOrderRepairDao.getDistance(map);
        if ("1".equals(MapUtils.getString(map, "IsOutside", ""))) {
            //获取距离
            //服务站经纬度
            String stationLonLat = StationLatLon.get("PositionLon") + "," + StationLatLon.get("PositionLat");
            String FaultLonLat = map.get("LocLon") + "," + map.get("LocLat");
            try {
                distance = GetDistance.getDistance(stationLonLat, FaultLonLat);
                map.put("GuessDistance", distance);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                //返回客户
                ParameterTool.writeResponse(response, SMSEnum.type29.getIndex(), SMSEnum.type29.getName());
                return null;
            }
        } else {
            map.put("Location", MapUtils.getString(StationLatLon, "Address"));
            map.put("LocLat", MapUtils.getDouble(StationLatLon, "PositionLat"));
            map.put("LocLon", MapUtils.getDouble(StationLatLon, "PositionLon"));
            map.put("LocProvince", MapUtils.getString(StationLatLon, "Province"));
            map.put("LocCity", MapUtils.getString(StationLatLon, "City"));
        }

        //售时工单外出时工单状态为待区域服务经理审核，不外出就是代派技师
        String orderStatus = "2";
        int isOutside = MapUtils.getIntValue(map, "IsOutside", -1);
        if (isOutside == 0) orderStatus = "6";
        map.put("OrderStatus", orderStatus);
        //step2:同步至CRM接口
        Map<String, Object> tbMap = APP2CRM_WorkOrder_Convert(map, 1, "XCEC");
        String OrderNoCRM = "";
        //同步工单信息到crm的状态和信息
        int syncOrderInfoStatus = 0;
        String syncOrderInfomessage = "";
        try {
            CRMResponeEntity CRMres = CRMApiUtils.getCRMServiceApi().syncSaleWorkOrderToCrmXCEC(tbMap,workOrderSynchro);
            if (CRMres.getStatus() != 0) {
                // APP同步工单信息到CRM系统失败
                log.error("XCEC服务站创建售时工单同步工单信息至CRM失败，状态：" + CRMres.getStatus() + "，用户信息:" + CRMres.getMessage());
                saveResult = -1;
                syncOrderInfoStatus = CRMres.getStatus();
                syncOrderInfomessage = CRMres.getMessage();
                workOrderSynchro.setFailReason(null != syncOrderInfomessage ? syncOrderInfomessage : "返回值空");
                workOrderSynchro.setSyncStatus(0);
            } else {
                if (CRMres.getData().containsKey("crmNo")) {
                    OrderNoCRM = CRMres.getData().getString("crmNo");
                    workOrderSynchro.setOrderNoCrm(OrderNoCRM);
                    workOrderSynchro.setSyncStatus(1);
                }
                map.put("OrderNoCrm", OrderNoCRM);
                //step1:保存工单信息

            }
        } catch (Exception e) {
            //APP同步工单信息到CRM系统失败
            log.error("XCEC服务站创建售时工单同步工单信息至CRM失败：" + e.getMessage(), e);
            saveResult = -1;
            syncOrderInfoStatus = 30;
            syncOrderInfomessage = "XCEC服务站创建售时工单同步工单信息至CRM失败：" + e.getMessage();
            workOrderSynchro.setFailReason(null != syncOrderInfomessage ? syncOrderInfomessage : "返回值空");
            workOrderSynchro.setSyncStatus(0);
        }

        if (syncOrderInfoStatus != 0) {
            ParameterTool.writeResponse(response, syncOrderInfoStatus, syncOrderInfomessage);
            return null;
        }
        saveResult = workOrderRepairDao.CreateWorkOrder(map);
        if (saveResult <= 0) {
            //工单信息保存失败
            ParameterTool.writeResponse(response, SMSEnum.type99.getIndex(), SMSEnum.type99.getName());
            return null;
        }
        String esn = MapUtils.getString(map, "ESN");
        Map<String, Object> engineMsgMap = engineMsgDao.getSMNByESN(esn);
        Map<String, Object> engineDataMap = new HashMap<>();
        engineDataMap.put("ESN", esn);
        engineDataMap.put("SMN", MapUtils.getString(map, "SMN", ""));
        engineDataMap.put("equipmentNo", MapUtils.getString(map, "VIN", ""));
        engineDataMap.put("vehicleCompany", MapUtils.getString(map, "OEMName", ""));
        engineDataMap.put("WarrantyStartDate", MapUtils.getString(map, "WarrantyStartDate", ""));
        engineDataMap.put("serviceChannel", "XCEC");
        engineDataMap.put("EnginePurpose", MapUtils.getString(map, "EnginePurpose", ""));
        engineDataMap.put("EngineSeries", MapUtils.getString(map, "EngineSeries", ""));
        if (MapUtils.isNotEmpty(engineMsgMap)) {
            //更新发动机基础数据表
            engineDataMap.put("Updator", userT.getId());
            engineDataMap.put("UpdateTime", LocalTimeUtil.getRealCurrentTime());
            int updateCount = engineMsgDao.updateMsgByEsn(engineDataMap);
        } else {
            //插入发动机基础数据表
            engineDataMap.put("Creator", userT.getId());
            engineDataMap.put("Createtime", LocalTimeUtil.getRealCurrentTime());
            int insertCount = engineMsgDao.insertSelective(engineDataMap);
        }


		//step1:保存工单信息
//		saveResult = workOrderRepairDao.CreateWorkOrder(map);


        //判断工单是否保存成功
        if (saveResult > 0) {
            //记录用户行为日志（需要把上面保存成功的工单Id放进map中）
            workOrderRepairDao.saveOperation(map);
            workOrderSynchro.setOrderNo(OrderNo);
            workOrderSynchro.setChannelName("XCEC");
            workOrderSynchro.setProcessStatus(1);
            workOrderSynchro.setOrderInfo(JSON.toJSONString(tbMap));
            workOrderSynchroService.add(workOrderSynchro);

            // xcec站长创建售时工单     不外出不推送消息，外出需要给区域服务经理发送消息,并且负责人是区域服务经理
            if ("2".equals(orderStatus)) {
                //保存工单负责人信息
                for (Map<String, Object> amap : areaManagerMap) {
                    map.put("PrincipalId", amap.get("ID"));
                    map.put("IsPrincipal", 1);
                    workOrderRepairDao.savePrincipal(map);
                }
                //推送消息
                List<Map<String, Object>> sendList = new ArrayList<>(areaManagerMap);
                //准备发送信息
                Map<String, Object> otherMap = new HashMap<String, Object>();
                String smsgbody = xcecSaleAreaManagerMsg;
                Map<String, Object> stationMsg = serviceStationDao.getServiceStationById(Long.parseLong(serviceStationId));
                smsgbody = String.format(smsgbody, MapUtils.getString(stationMsg, "StationName", ""), OrderNo);
                otherMap.put("msgBody", smsgbody);
                otherMap.put("msgTransMsg", smsgbody);
                otherMap.put("msgTitle", msgtitle);
                otherMap.put("function", msgFunctionNew);
                otherMap.put("category", msgCategoryNew);
                //开始发送消息(返回结果集为发送结果，要存入数据库，作为记录)
                List<Map<String, Object>> sendMsgResultList = asyncTask.sendMsg(map, sendList, 1, 1, otherMap);
                //将信息发送结果记录到数据库
                if (CollectionUtils.isNotEmpty(sendMsgResultList)) {
                    workOrderRepairDao.saveMsgOperation(sendMsgResultList);
                }
            }

            //返回客户端通知工单保存成功
            JSONObject jsb = new JSONObject();
            jsb.put("OrderId", map.get("OrderId"));
            jsb.put("OrderNo", OrderNo);
            ParameterTool.writeSuccessResponse(response, jsb);
            return null;
        } else {
            //工单信息保存失败
            ParameterTool.writeResponse(response, SMSEnum.type99.getIndex(), SMSEnum.type99.getName());
            return null;
        }
    }


    /**
     * 验证参数是否为空
     *
     * @param map
     * @return
     */
    private boolean chechParameters(Map<String, Object> map) {
        if (StringUtils.isBlank(MapUtils.getString(map, "ESN")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "ServiceStationId")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "RequestType")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "CustomerName")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "CustomerPhone")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "ServiceInitPlan")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "IsOutside")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "Location")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "FaultLevel")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "LocLon")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "LocLat")))
            return false;
        if (StringUtils.isBlank(MapUtils.getString(map, "CustomerComplaint")))
            return false;
        return true;
    }

    /**
     * 取消工单接口
     *
     * @throws Exception
     */
    @Override
    @Transactional
    public ModelAndView cancelWorkOrder(Map<String, Object> map) {
        // TODO Auto-generated method stub
        HttpServletRequest request = (HttpServletRequest) map.get("request");
        HttpServletResponse response = (HttpServletResponse) map.get("response");
        try {
            //返回JSON对象
            JSONObject obj = new JSONObject();
            //处理用户Id
            String ProcessorId = map.get("ProcessorId").toString();
            UserT userT = loginDao.getUserByid(ProcessorId);
            long lProcessorId = userT.getId();
            String ProcessorName = userT.getContact();
            String ProcessorPhone = userT.getPhone();
            map.put("ProcessorId", lProcessorId);
            map.put("ProcessorName", ProcessorName);
            map.put("ProcessorPhone", ProcessorPhone);
            //根据页面传过来的工单Id查询工单最新状态
            Map<String, Object> workOrderMap = new HashMap<String, Object>();
            workOrderMap = workOrderRepairDao.getCurrentWorkOrder(map);
            int orderStatus = 15;  //除了ccec都是这个状态  ccec点击取消   状态为取消中 30
            if (!workOrderMap.isEmpty()) {
                Integer orderChannel = MapUtils.getInteger(workOrderMap, "OrderChannel");
                CompanyT companyT = companyTDao.getCompanyInfoByCompanyID(MapUtils.getLongValue(workOrderMap, "OrderChannel"));
                CompanyT ccecChannelCompany = companyTDao.getCompanyInfoByCompanyNo("CCEC");
                if (companyT.getId() == ccecChannelCompany.getId()) {  //当前渠道是ccec   重新赋值工单状态
                    orderStatus = 30;  //取消中
                }
                //(先获取取消之前工单的状态)
                String beforeOrderStatus = MapUtils.getString(workOrderMap, "OrderStatus", "");
                int intbeforeOrderStatus = Integer.parseInt(beforeOrderStatus);
                //保存服务站信息
                map.put("ServiceStationId", MapUtils.getString(workOrderMap, "ServiceStationId", ""));
                //判断当前工单状态是否是可取消状态
                //若用户当前页面未及时刷新单击工单取消，后台根据此状态逻辑判断是否可取消，若用户不可取消工单时，后台提示：“工单状态已变更，请刷新APP再试”
                Boolean canCancel = Boolean.FALSE;
                if (orderChannel.equals(1)) {
                    // 工单状态=工单已创建 1/待区域工程师处理 18/待服务商接单 4/服务商拒单 5/待派服务技师 6/待服务技师接单7/技师已接单8/技师已拒单9/已出发10/已到达11，用户可以取消工单，若工单为其他状态，不显示取消工单按钮，
                    if (intbeforeOrderStatus == 1 || intbeforeOrderStatus == 18 || intbeforeOrderStatus == 4 || intbeforeOrderStatus == 5 || intbeforeOrderStatus == 6 || intbeforeOrderStatus == 7 || intbeforeOrderStatus == 8 || intbeforeOrderStatus == 9 || intbeforeOrderStatus == 10 || intbeforeOrderStatus == 11) {
                        canCancel = Boolean.TRUE;
                    }
                } else {
                    if (companyT.getCompanyNo().equals("CCEC")) {
                        // 1 已创建/23  待400审核-工单创建/24  待400审核-（400回访/诊断中/继续服务/待更新）/25  400审核不通过-工单驳回/4  待服务商接单/5  待服务商拒单/6  待派服务技师/7  待服务技师接单/8  技师已接单/9  技师已拒单/10  已出发/11 已到达
                        // 用户可以取消工单，若工单为其他状态，不显示取消工单按钮
                        if (intbeforeOrderStatus == 1 || intbeforeOrderStatus == 23 || intbeforeOrderStatus == 24 || intbeforeOrderStatus == 25 || intbeforeOrderStatus == 4 || intbeforeOrderStatus == 5 || intbeforeOrderStatus == 6 || intbeforeOrderStatus == 7 || intbeforeOrderStatus == 8 || intbeforeOrderStatus == 9 || intbeforeOrderStatus == 10 || intbeforeOrderStatus == 11) {
                            canCancel = Boolean.TRUE;
                        }
                    } else {
                        // 工单状态=工单已创建 1/待区域服务经理审核 2/待服务商接单 4/服务商拒单 5/待派服务技师 6/待服务技师接单7/技师已接单8/技师已拒单9/已出发10/已到达11，用户可以取消工单，若工单为其他状态，不显示取消工单按钮
                        if (intbeforeOrderStatus == 1 || intbeforeOrderStatus == 2 || intbeforeOrderStatus == 4 || intbeforeOrderStatus == 5 || intbeforeOrderStatus == 6 || intbeforeOrderStatus == 7 || intbeforeOrderStatus == 8 || intbeforeOrderStatus == 9 || intbeforeOrderStatus == 10 || intbeforeOrderStatus == 11) {
                            canCancel = Boolean.TRUE;
                        }
                    }

                }
                // 可以取消
                if (canCancel) {
                    //信息发送记录结果
                    int saveMsgOperationResult = -1;
                    //取消工单默认将工单状态置为 已取消
                    map.put("OrderStatus", orderStatus);
                    //设置取消时间
                    map.put("CancelTime", LocalTimeUtil.getRealCurrentTime());
                    //终端用户或400如果在经理审批状态取消工单，服务站不应该能看到
                    if(intbeforeOrderStatus == 2
                            &&((MapUtils.getIntValue(workOrderMap,"OrderSource") == 0 && MapUtils.getLong(workOrderMap,"Creator") == lProcessorId)
                            || MapUtils.getIntValue(workOrderMap,"OrderSource") == 2)) {
                        int count = workOrderFlowTDao.getCountByOrderId(MapUtils.getLong(workOrderMap,"OrderId"));
                        if(count <= 0){
                            map.put("isShowStation", -1);
                        }
                    }
                    //取消原因（如果输入的原因不为空，则追加到选择的原因之后）
                    if (!"".equals(MapUtils.getString(map, "EditContent", ""))) {
                        map.put("CancelReason", map.get("CancelReason") + ":" + map.get("EditContent").toString().trim());
                    }
                    //将取消原因同步至操作日志
                    map.put("ProcessComment", map.get("CancelReason"));
                    map.put("UpdateTime", (String) map.get("updateTime"));  //前端传来的这条工单的修改时间

                    //step1:将工单表中的工单状态置为取消
                    int updateResult = workOrderRepairDao.updateWorkOrderStatus(map);

                    if (updateResult == 0) {  //工单状态没修改成功
                        obj.put("status", SMSEnum.type21.getIndex());
                        obj.put("msg", SMSEnum.type21.getName());
                        obj.put("data", "");
                        //返回客户
                        ParameterTool.writeResponse(response, obj.toString());
                        return null;
                    }
                    workOrderMap.put("CancelReason", MapUtils.getString(map, "CancelReason"));
                    //将工单状态同步至CRM
                    Map<String, Object> tbMap = new HashMap<String, Object>();
                    if (orderChannel.equals(1)) {
                        // 渠道为DBU
                        tbMap = syncOrderStatusMap(workOrderMap, orderStatus);
                        Long orderId = MapUtils.getLongValue(map,"OrderId");
                        //修改campaign任务状态
                        updateCampaignStatus(orderId,5,UserThreadLocal.get().getId(),"终端用户取消服务工单");
                    } else {
                        // 渠道为DCEC,XCEC,CCEC
                        tbMap = OrderStatusToCrmMap(workOrderMap, map);
                        if (orderChannel.equals(4)) {  //当服务渠道为xcec，传经纬度，故障地点，手机串号
                            tbMap.put("phoneIMEI", MapUtils.getString(map, "IMEI", ""));
                            tbMap.put("positionLat", MapUtils.getFloatValue(map, "ProLocLat", 0));
                            tbMap.put("positionLon", MapUtils.getFloatValue(map, "ProLocLon", 0));
                            tbMap.put("location", MapUtils.getString(map, "ProLocation", ""));
                        }
                    }
                    tbMap.put("CCSSComplainerOrderNo", MapUtils.getString(workOrderMap, "OrderNoCrm", ""));
                    tbMap.put("CCSSOrderNo", MapUtils.getString(workOrderMap, "CCSSOrderNo", ""));
                    tbMap.put("refuseReason", map.get("CancelReason"));  //取消原因传给CRM
                    try {

                        /**
                         * TODO 判断服务工单的来源，增加参数
                         */
                        CRMResponeEntity CRMres = CRMApiUtils.getCRMServiceApi().syncOrderStatusToCrm(workOrderMap.get("Abbreviation").toString(), platformServiceDao, redisClientUtils, tbMap,null);
                        if (CRMres.getStatus() != 0) {
                            //APP同步工单信息到CRM系统失败
                            log.error("用户取消工单同步工单状态至CRM失败，状态：" + CRMres.getStatus() + "，失败信息:" + CRMres.getMessage());
                        }
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        //APP同步工单信息到CRM系统失败
                        log.error("用户取消工单同步工单状态至CRM失败：" + e.getMessage(), e);
                    }
                    if (updateResult > 0) {
                        String serviceSubtype = MapUtils.getString(workOrderMap, "ServiceSubtype", "");
                        String sellType = MapUtils.getString(workOrderMap, "SellType", "");
                        //准备信息发送必要参数
                        workOrderMap.put("ProcessorId", lProcessorId);
                        Map<String, Object> otherMap = new HashMap<String, Object>();
                        String orderNo = MapUtils.getString(workOrderMap, "OrderNo", "");
                        String scmsgbody = "";
                        String sctransmsg = "";
                        if ("CCEC".equals(companyT.getCompanyNo())) {
                            scmsgbody = cmsgbodyCCEC;
                            sctransmsg = ctransmsgCCEC;
                            String msg = "";
                            String fwOrderNo = MapUtils.getString(workOrderMap, "CCSSOrderNo", "");
                            if (StringUtils.isNotEmpty(fwOrderNo)) {
                                msg = orderNo + "（FW号" + fwOrderNo + "）";
                                scmsgbody = String.format(scmsgbody, msg);
                                sctransmsg = String.format(sctransmsg, msg);
                            } else {
                                scmsgbody = String.format(scmsgbody, orderNo);
                                sctransmsg = String.format(sctransmsg, orderNo);
                            }
                        } else {
                            scmsgbody = cmsgbody;
                            sctransmsg = ctransmsg;
                            scmsgbody = scmsgbody.replace("***", orderNo);
                            sctransmsg = sctransmsg.replace("***", orderNo);
                            if(orderChannel.equals(1)){
                                scmsgbody = scmsgbody + "属于\"" + sellType + "\"" + (StringUtils.isNotBlank(serviceSubtype) ? "-" + serviceSubtype : "") + "，";
                            }
                            scmsgbody = scmsgbody + "请查看!";
                            if(orderChannel.equals(1)){
                                sctransmsg = sctransmsg + "属于\"" + sellType + "\"" + (StringUtils.isNotBlank(serviceSubtype) ? "-" + serviceSubtype : "") + "，";
                            }
                            sctransmsg = sctransmsg + "请查看!";
                        }
                        otherMap.put("msgBody", scmsgbody);//(,,,,)
                        otherMap.put("msgTransMsg", sctransmsg);
                        otherMap.put("msgTitle", cmsgtitle);
                        otherMap.put("function", msgFunctionCancel);
                        otherMap.put("category", msgCategoryCancel);
                        //设置取消时间
                        map.put("CreateTime", LocalTimeUtil.getRealCurrentTime());
                        //更新成功，记录用户行为
                        workOrderRepairDao.saveOperation(map);
                        //step3:工单状态更新完成，给相关人员发消息（根据取消之前的工单状态给相关人员发消息）
                        // DBU工单
                        if (orderChannel.equals(1)) {
                            List<Map<String, Object>> sendList = new ArrayList<>();
                            Long workOrderId = MapUtils.getLong(workOrderMap, "ID");
                            // 非创建状态，进行消息推送
                            if (intbeforeOrderStatus != 1) {

                                //区域工程师都需要通知
                                Map<String, Object> engineerMap = workOrderOperatorRelationDao.getOperatorByOrderId(workOrderId);
                                Map<String, Object> sendMap = new HashMap<>(3);
                                sendMap.put("ID", MapUtils.getLong(engineerMap, "UserId"));
                                sendMap.put("phone", MapUtils.getString(engineerMap, "Phone"));
                                UserT engineerUser = loginDao.getUserByUserId(MapUtils.getLong(engineerMap, "UserId"));
                                if (null != engineerUser) {
                                    sendMap.put("clientId", redisClientUtils.hget(RedisKeys.geTuiKey(), engineerUser.getUserName()));
                                }
                                sendList.add(sendMap);

                                // 待服务商接单/待派服务技师/待服务技师接单通知服务商站长信息员
                                if (intbeforeOrderStatus == 4 || intbeforeOrderStatus == 6 || intbeforeOrderStatus == 7) {
                                    Map<String, Object> queryMap = new HashMap<>(2);
                                    queryMap.put("orderId", workOrderId);
                                    List<Map<String, Object>> managerList = dbuRemindTaskTDao.selectServiceStationManagerList(queryMap);
                                    if (CollectionUtils.isNotEmpty(managerList)) {
                                        for (Map<String, Object> managerMap : managerList) {
                                            Map<String, Object> subSendMap = new HashMap<>(3);
                                            subSendMap.put("ID", MapUtils.getLong(managerMap, "ID"));
                                            subSendMap.put("phone", MapUtils.getString(managerMap, "Phone"));
                                            subSendMap.put("clientId", redisClientUtils.hget(RedisKeys.geTuiKey(), MapUtils.getString(managerMap, "UserName")));
                                            sendList.add(subSendMap);
                                        }
                                    }
                                }

								// 待服务技师接单通知技师
								if(intbeforeOrderStatus == 7){
									Map<String, Object> queryMap = new HashMap<>(2);
									queryMap.put("orderId", workOrderId);
									queryMap.put("orderStatus", intbeforeOrderStatus);
									List<Map<String,Object>> technicianList = dbuRemindTaskTDao.selectTechnicianList(queryMap);
									if(CollectionUtils.isNotEmpty(technicianList)){
										for(Map<String,Object> technicianMap:technicianList){
											Map<String,Object> subSendMap = new HashMap<>(3);
											subSendMap.put("ID",MapUtils.getLong(technicianMap,"ID"));
											subSendMap.put("phone",MapUtils.getString(technicianMap,"Phone"));
											subSendMap.put("clientId",redisClientUtils.hget(RedisKeys.geTuiKey(),MapUtils.getString(technicianMap,"UserName")));
											sendList.add(subSendMap);
										}
									}
								}
							}
							// 发送相关人员
							if(CollectionUtils.isNotEmpty(sendList)){
								List<Map<String,Object>> sendMsgResultList = asyncTask.sendMsg(workOrderMap,sendList,1,1,otherMap);
								//将信息发送结果记录到数据库
								if(CollectionUtils.isNotEmpty(sendMsgResultList)){
									workOrderRepairDao.saveMsgOperation(sendMsgResultList);
								}
							}
							//dbu的工单需要推送公众号消息   dbu微信公众号查看工单详情url
							if (orderChannel == 1) {
								String dbuWechatWorkOrderInfoUrl = propertiesUtils.getPropertiesValue("DBUWechatWorkOrderInfoUrl");
								//Map<String, Object> weChatUserRelationTMap = weChatUserRelationTDao.getWeChatUserRelationTByUserPhone(us.get(0).getPhone());
								//if (MapUtils.isNotEmpty(weChatUserRelationTMap)) {
								//拼公众号中查看详情的url
								String urlFormat = String.format(dbuWechatWorkOrderInfoUrl, workOrderId);
								//推送微信公众号消息
								String firstData = "您有一条重要的工单状态信息";
								String keyWord1 = "编号：" + MapUtils.getString(workOrderMap, "OrderNo", "");
								String keyWord2 = "您有工单取消，请查看。";
								String keyWord3 = Dictionaries.OrderStatus_15.getName();
								String keyWord4 = UserThreadLocal.get().getContact();
								String remark = "请点击详情查看工单内容";
								iOrderPushMessageService.sendOrderMessage(workOrderId, urlFormat, firstData, keyWord1,
										keyWord2, keyWord3, keyWord4, remark);
								//}
							}
							ParameterTool.writeSuccessResponse(response);
						}else {	// DBU以外渠道
							map.put("roleNo", "'R0070'");
							List<Map<String,Object>> AreaManagerMap = new ArrayList<Map<String,Object>>();
							map.put("OrderChannel", workOrderMap.get("OrderChannel"));
							AreaManagerMap = workOrderRepairDao.getAreaManager(map);
							List<Map<String,Object>> sendList = new ArrayList<Map<String,Object>>();
							//工单状态为待服务经理确认，给服务经理发消息，
							if(intbeforeOrderStatus==2) {
								if(null!=AreaManagerMap && AreaManagerMap.size()>0) {
									sendList.addAll(AreaManagerMap) ;
									//开始发送消息(返回结果集为发送结果，要存入数据库，作为记录)
									List<Map<String,Object>> sendMsgResultList = asyncTask.sendMsg(workOrderMap,sendList,1,1,otherMap);
									//将信息发送结果记录到数据库
									if(CollectionUtils.isNotEmpty(sendMsgResultList)){
										saveMsgOperationResult = workOrderRepairDao.saveMsgOperation(sendMsgResultList);
									}
								}
							}
							//如果工单状态为待服务商接单或代派服务技师，则给 服务经理，服务商站长，服务商信息员发消息，提醒内容为“您有工单取消，工单号XXX，请查看。”；
							if(intbeforeOrderStatus==4 || intbeforeOrderStatus==6) {
								map.put("roleNo", "'R0041','R0069'");
								sendList = workOrderRepairDao.getSendList(map,Arrays.asList("R0041","R0069"));
								if(null!=AreaManagerMap && AreaManagerMap.size()>0) {
									sendList.addAll(AreaManagerMap);
								}
								if(null!=sendList && sendList.size()>0) {
									//开始发送消息(返回结果集为发送结果，要存入数据库，作为记录)
									/**
									 * 20210812 【短信通知】【XCEC】短信通知取消
									 * 取消以下短信发送：
									 * 1）区域经理	新工单提醒	实时发送：您有新工单信息，工单号XXX，请查看。
									 * 2）区域经理	新工单提醒（400指派给区域服务经理）实时发送：您有新工单信息，工单号XXX，请尽快处理。
									 * 3）区域经理	工单接受提醒	实时发送：您有工单被接受，工单号XXX，请查看。
									 * 4）区域经理	技师接单提醒	实时发送：您有工单被接单，工单号XXX，请查看。
									 * 5）区域经理	技师已出发提醒  实时发送：您的工单服务技师已出发，工单号XXX，请查看。
									 * 6）区域经理	技师开始维修提醒	实时发送：您的工单服务技师开始维修，工单号XXX，请查看。
									 * 7）区域经理	工单取消提醒	实时发送：您有工单取消，工单号XXX，请查看。	- 当前
									 * 8）区域经理	服务商关闭工单提醒	实时发送：您有工单被关闭，工单号XXX，请查看。
									 */
									List<Map<String,Object>> sendMsgResultList = asyncTask.sendMsg(workOrderMap,sendList,0,1,otherMap);
									//将信息发送结果记录到数据库
									if(CollectionUtils.isNotEmpty(sendMsgResultList)){
										saveMsgOperationResult = workOrderRepairDao.saveMsgOperation(sendMsgResultList);
									}
								}
							}
							//
							if(intbeforeOrderStatus>=7 && intbeforeOrderStatus<=11) {
								map.put("roleNo", "'R0041','R0069'");
								sendList = workOrderRepairDao.getSendList(map,Arrays.asList("R0041","R0069"));
								//查找指派给了哪个服务技师
								map.put("ServiceStatus", 7);//待派服务技师的工单状态（serviceStatus）
								Map<String,Object> serviceTech = workOrderRepairDao.getServiceTech(map);
								if(null!=serviceTech && serviceTech.size()>0) {
									sendList.add(serviceTech);
								}
								if(null!=AreaManagerMap && AreaManagerMap.size()>0) {
									sendList.addAll(AreaManagerMap);
								}
								if(null!=sendList && sendList.size()>0) {
									//开始发送消息(返回结果集为发送结果，要存入数据库，作为记录)
									List<Map<String,Object>> sendMsgResultList = asyncTask.sendMsg(workOrderMap,sendList,1,1,otherMap);
									//将信息发送结果记录到数据库
									if(CollectionUtils.isNotEmpty(sendMsgResultList)){
										saveMsgOperationResult = workOrderRepairDao.saveMsgOperation(sendMsgResultList);
									}
								}
							}
							//dcec的工单需要推送公众号消息   dcec微信公众号查看工单详情url

							Integer orderSource;
							try {
								orderSource = MapUtils.getInteger(workOrderMap, "orderSource");
								if (orderChannel == 3 && orderSource == 6) {
									Long workOrderId = MapUtils.getLong(workOrderMap, "ID");
									String dbuWechatWorkOrderInfoUrl = propertiesUtils.getPropertiesValue("DBUWechatWorkOrderInfoUrl");
									//Map<String, Object> weChatUserRelationTMap = weChatUserRelationTDao.getWeChatUserRelationTByUserPhone(us.get(0).getPhone());
									//if (MapUtils.isNotEmpty(weChatUserRelationTMap)) {
									//拼公众号中查看详情的url
									String urlFormat = String.format(dbuWechatWorkOrderInfoUrl, workOrderId);
									//推送微信公众号消息
									//推送微信公众号消息
									String firstData = "您有一条重要的工单状态信息";
									String keyWord1 = "编号：" + MapUtils.getString(workOrderMap, "OrderNo", "");
									String keyWord2 = "您有工单取消，请查看。";
									String keyWord3 = Dictionaries.OrderStatus_15.getName();
									String keyWord4 = UserThreadLocal.get().getContact();
									String remark = "请点击详情查看工单内容";
									iOrderPushMessageService.sendOrderMessage(workOrderId, urlFormat, firstData, keyWord1,
											keyWord2, keyWord3, keyWord4, remark);
								}
							} catch (Exception e) {
								e.printStackTrace();
							}

							//工单取消处理完成，返回结果
							obj.put("status", SMSEnum.type0.getIndex());
							obj.put("msg", SMSEnum.type0.getName());
							obj.put("data", "");
							//返回客户
							ParameterTool.writeResponse(response, obj.toString());
							obj = null;
							return null;
						}
					}
				}else {
					//后台提示：“工单状态已变更，请刷新APP再试”
					obj.put("status", SMSEnum.type21.getIndex());
					obj.put("msg", SMSEnum.type21.getName());
					obj.put("data", "");
					//返回客户
					ParameterTool.writeResponse(response, obj.toString());
					obj = null;
					return null;
				}

			}else {
				//未查询到工单信息
				obj.put("status", SMSEnum.type20.getIndex());
				obj.put("msg", SMSEnum.type20.getName());
				obj.put("data", "");
				//返回客户
				ParameterTool.writeResponse(response, obj.toString());
				obj = null;
				return null;
			}


		} catch (Exception ex) {
			// TODO: handle exception
			log.error(ex.getMessage(), ex);
			ParameterTool.writeErrorResponse(response);
			//主动回滚事务
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
		return null;
	}


    //修改campaign任务状态
    void updateCampaignStatus(Long orderId,Integer status,Long userId,String remark){
        //查看当前工单是否存在campaign任务
        List<Map<String,Object>> campaignList = campaignTaskInfoDao.getCampaignListByOrderId(orderId);
        if(CollectionUtils.isNotEmpty(campaignList)){
            String currentTime = LocalTimeUtil.getRealCurrentTime();
            //修改campaign任务状态
            campaignTaskInfoDao.updateCampaignTaskStatus(status,userId,currentTime,orderId);
            //插入操作记录表
            for(Map<String,Object> campaign : campaignList){
                CampaignTaskFlow campaignTaskFlow = new CampaignTaskFlow();
                campaignTaskFlow.setCampaignTaskInfoId(MapUtils.getLongValue(campaign,"id"));
                campaignTaskFlow.setCampaignTaskStatus(status);
                campaignTaskFlow.setRemark(remark);
                campaignTaskFlowDao.insert(campaignTaskFlow,userId,currentTime);
            }
        }
    }


    @Override
    public void validationWorkOrder(Map<String, Object> map) {
        Map<String, Object> resultMap = new HashMap<>();
        String systemTime = LocalTimeUtil.getRealCurrentTime();
        HttpServletResponse response = (HttpServletResponse) map.get("response");

        String workOrderId = MapUtils.getString(map, "workOrderId");

        Integer queryOverTimeType = MapUtils.getInteger(map, "overTimeType");

        if (StringUtils.isEmpty(workOrderId)) {
            ParameterTool.writeErrorResponse(response, -5);
            return;
        }

        Integer overTimeType = null;
        /**
         * 3.1.0XCEC-服务工单-技师点维修完成时,增加8小时超时校验(点击维修完成时间 - 工单创建时间 > 8)
         */
        if (queryOverTimeType != null && queryOverTimeType.equals(OverTimeType.TYPE21.getCode())) {

            /**
             * 从Redis中查询出当前是工单是否已经上传过超时原因了，如果已经上传过超时原因，那么不需要在上传超时原因
             */
            Object value = redisClientUtils.getObject(RedisKeys.overTimeWorkOrderTypeKey(workOrderId, queryOverTimeType));

            /**
             * value为null时说明 1.缓存过期(缓存1个月后自动删除) 2.工单未上传超时原因
             */
            if (null == value) {
                try {
                    overTimeType = isWorkOrderRepairTimeoutForXCEC(Long.parseLong(workOrderId), response);
                } catch (RuntimeException e) {
                    log.error(e.getMessage(), e);
                    return;
                }
            }
        } else {
            overTimeType = (Integer) redisClientUtils.getObject(RedisKeys.overTimeWorkOrderTypeKey(workOrderId, queryOverTimeType));
        }


        resultMap.put("workOrderId", workOrderId);
        if (null == overTimeType || !overTimeType.equals(queryOverTimeType)) {
            DBUMarketTypeTimeout(resultMap, systemTime, workOrderId);
        } else {
            List<Map<String, Object>> list = dbuRemindTaskTDao.selectWorkOrderOverTime(Long.valueOf(workOrderId));
            if (list.size()>0){
                resultMap.put("isOverTime", 0);
            }else{
            resultMap.put("isOverTime", 1);
            resultMap.put("overTimeType", overTimeType);}
        }
        ParameterTool.writeSuccessResponse(response, resultMap);
    }

    private void DBUMarketTypeTimeout(Map<String, Object> resultMap, String systemTime, String workOrderId) {
        List<Map<String, Object>> workOrderList = dbuRemindTaskTDao.selectWorkOrderWithUnfinishedById(systemTime, Long.valueOf(workOrderId));
        List<Map<String, Object>> list = dbuRemindTaskTDao.selectWorkOrderOverTime(Long.valueOf(workOrderId));
        if (list.size() > 0) {
            resultMap.put("isOverTime", 0);
            return;
        }
        if (CollectionUtils.isNotEmpty(workOrderList)) {
            Map<String, Object> orderMap = workOrderList.get(0);

            String MarketType = MapUtils.getString(orderMap, "MarketType");
            Integer orderStatus = MapUtils.getInteger(orderMap, "OrderStatus");
            if (null != orderStatus && (orderStatus == 11 || orderStatus == 12)) {
                Long isOutside = MapUtils.getLong(orderMap, "IsOutside", 0L);
                Long overTimeStatus = 0L;
                if (isOutside == 0) {
                    String receiveTimeEngineer = MapUtils.getString(orderMap, "ReceiveTimeEngineer");
                    Date date = Date_Util.toDate(receiveTimeEngineer, "yyyy-MM-dd hh:mm");
                    //不外出的接单时间
                    overTimeStatus = Long.valueOf(Date_Util.getMinutes(date, Date_Util.toDate(LocalTimeUtil.getRealCurrentTime(), "yyyy-MM-dd hh:mm")));
                } else if (isOutside == 1) {
                    String arriveTime = MapUtils.getString(orderMap, "ArriveTime");
                    Date date = Date_Util.toDate(arriveTime, "yyyy-MM-dd hh:mm");
                    //外出的接单时间
                    overTimeStatus = Long.valueOf(Date_Util.getMinutes(date, Date_Util.toDate(LocalTimeUtil.getRealCurrentTime(), "yyyy-MM-dd hh:mm")));
                }
                if (MarketClassType.BUS.equals(MarketType) || MarketClassType.TRUCK.equals(MarketType)) {
                    if (overTimeStatus > 60 * 3) {  //车用：维修完成时间-到达时间（非外出，开始维修时间）>3小时；
                        log.info("车用类型符合判断工单号：" + MapUtils.getString(orderMap, "OrderNo"));
                        resultMap.put("isOverTime", 1);
                        resultMap.put("overTimeType", 7);
                        setOverTimeKey(Long.valueOf(workOrderId), OverTimeType.TYPE7);
                    }
                } else if (MarketClassType.CONSTRUCTION.equals(MarketType)) {
                    if (overTimeStatus > 390) { //工业：维修完成时间-到达时间（非外出，开始维修时间）>6小时；  sprint24改为6.5
                        log.info("工业类型符合判断工单号：" + MapUtils.getString(orderMap, "OrderNo"));
                        resultMap.put("isOverTime", 1);
                        resultMap.put("overTimeType", 7);
                        setOverTimeKey(Long.valueOf(workOrderId), OverTimeType.TYPE7);
                    }
                } else {
                    if (overTimeStatus > 60 * 12) {//其他：维修完成时间-到达时间（非外 出，开始维修时间）>12小时。
                        log.info("其他类型符合判断工单号：" + MapUtils.getString(orderMap, "OrderNo"));
                        resultMap.put("isOverTime", 1);
                        resultMap.put("overTimeType", 7);
                        setOverTimeKey(Long.valueOf(workOrderId), OverTimeType.TYPE7);
                    }
                }
            }
        } else {
            resultMap.put("isOverTime", 0);
        }
    }
    public void setOverTimeKey(Long orderId,OverTimeType overTimeType){
        String workOrderId = String.valueOf(orderId);
        Integer code = overTimeType.getCode();
        redisClientUtils.setObject(RedisKeys.overTimeWorkOrderTypeKey(workOrderId,code), code,60*60*24*30);
    }
    /**
     * 3.1.0 XCEC-服务工单-技师点维修完成时,增加8小时超时校验(点击维修完成时间 - 工单创建时间 > 8)
     */
    public Integer isWorkOrderRepairTimeoutForXCEC(long workOrderId, HttpServletResponse response) {
        // 获取当前服务工单的创建时间
        Map<String, Object> orderMap = workOrderTDao.getOrderById(workOrderId);
        if (MapUtils.isEmpty(orderMap)) {
            ParameterTool.writeErrorResponse(response, -41);
            throw new RuntimeException("服务工单不存在 工单ID:" + workOrderId);
        }

        String createTime = MapUtils.getString(orderMap, "CreateTime");
        // 当前系统时间
        String currentTime = LocalTimeUtil.getRealCurrentTime();
        long hours = LocalTimeUtil.getDurationSeconds(createTime, currentTime);
        // 是否超时8小时
        if ((hours / 3600.0) > 8) {
            return OverTimeType.TYPE21.getCode();
        }
        return null;
    }


    @Override
    public void getWorkOrderOverTimeReason(Map<String, Object> map) {
        HttpServletResponse response = (HttpServletResponse) map.get("response");
        List<Map<String, Object>> list = (List<Map<String, Object>>) redisClientUtils.getObject("overTimeReason");
        if (CollectionUtils.isEmpty(list)) {
            //获取超时原因列表，并放入redis中
            list = workOrderReasonDao.getWorkOrderReason(1);
            if (CollectionUtils.isNotEmpty(list)) {
                redisClientUtils.setObject("overTimeReason", list, 300);
            }
        }

        Map<String, Object> data = new HashMap<>();
        List<Map<String, Object>> reasonList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (Map<String, Object> sub : list) {
                Map<String, Object> result = new HashMap<>();
                result.put("reasonKey", MapUtils.getInteger(sub, "ReasonKey"));
                result.put("reasonMessage", MapUtils.getString(sub, "ReasonMessage"));
                result.put("reasonType", MapUtils.getInteger(sub, "ReasonType"));
                reasonList.add(result);
            }
        }
        data.put("reasonList", reasonList);
        ParameterTool.writeSuccessResponse(response, data);
    }

    @Override
    @Transactional
    public void workOrderOverTimeReason(Map<String, Object> map) {
        HttpServletResponse response = (HttpServletResponse) map.get("response");

        String workOrderId = MapUtils.getString(map, "workOrderId");
        Integer overTimeType = MapUtils.getInteger(map, "overTimeType");
        Integer orderStatus = MapUtils.getInteger(map, "orderStatus");

        /**
         * 3.1.0 XCEC-服务工单
         * 技师点维修完成时，(技师点击维修完成的时间 - 工单创建的时间 大于8小时)上传超时原因
         */
        if (OverTimeType.TYPE21.getCode().equals(overTimeType)) {
            techRepairTimeoutForXCEC(Long.parseLong(workOrderId),
                    overTimeType,
                    MapUtils.getInteger(map, "reasonKey"),
                    MapUtils.getString(map, "reasonMessage"),
                    MapUtils.getInteger(map, "reasonType"),
                    MapUtils.getString(map, "partInfo"),
                    response);
            return;
        }

        Integer cacheOverTimeType = (Integer) redisClientUtils.getObject(RedisKeys.overTimeWorkOrderTypeKey(workOrderId, overTimeType));
        if (null != cacheOverTimeType && overTimeType.equals(cacheOverTimeType)) {
            WorkOrderOverTime reason = new WorkOrderOverTime();
            if (cacheOverTimeType == 1 || cacheOverTimeType == 7) {
                WorkOrderT workOrderT = workOrderTDao.getWorkOrderTByOrderId(Long.valueOf(workOrderId));
                // 区域工程师处理超时
                if (cacheOverTimeType == 1) {
                    int orderSource = workOrderT.getOrderSource();
                    if (orderSource != 1) {
                        // 非服务商报单，下一状态为待服务商接单
                        reason.setOrderStatus(4);
                    } else {
                        // 服务商报单，下一状态为待服务技师接单
                        reason.setOrderStatus(6);
                    }
                }
                // 技师维修超时
                if (cacheOverTimeType == 7) {
                    String phone = workOrderT.getCustomerPhone();
                    List<UserT> userTList = loginDao.getUserByPhone(phone);
                    if (CollectionUtils.isEmpty(userTList)) {
                        // 工单报修人在系统中，下一个状态为待用户评价
                        reason.setOrderStatus(14);
                    } else {
                        // 工单报修人不在系统中，下一个状态为服务完成
                        reason.setOrderStatus(13);
                    }
                }
            } else {
                reason.setOrderStatus(orderStatus);
            }
            UserT userT = UserThreadLocal.get();
            reason.setOrderId(MapUtils.getLong(map, "workOrderId"));
            reason.setType(overTimeType);
            Integer reasonKey = MapUtils.getInteger(map, "reasonKey");
            reason.setReasonKey(reasonKey);
            String reasonMessage = MapUtils.getString(map, "reasonMessage");
            if (StringUtils.isEmpty(reasonMessage)) {
                reasonMessage = workOrderOverTimeReasonDao.getReasonMessageByReasonKey(reasonKey);
            }
            reason.setReasonMessage(reasonMessage);
            reason.setReasonType(MapUtils.getInteger(map, "reasonType"));
            reason.setPartInfo(MapUtils.getString(map, "partInfo"));
            reason.setUserId(userT.getId());
            reason.setCreator(userT.getId());
            reason.setCreateTime(LocalTimeUtil.getRealCurrentTime());
            workOrderOverTimeReasonDao.insertSelective(reason);
            redisClientUtils.delkey(RedisKeys.overTimeWorkOrderTypeKey(workOrderId, overTimeType));
        } else {
            ParameterTool.writeResponse(response, 1, "无效的超时类型");
        }
        ParameterTool.writeSuccessResponse(response);
    }


    /**
     * 3.1.0
     * XCEC 技师维修超时上传超时原因
     */
    public void techRepairTimeoutForXCEC(long workOrderId, Integer overTimeType, Integer reasonKey, String reasonMessage, Integer reasonType, String partInfo, HttpServletResponse response) {
        WorkOrderOverTime reason = new WorkOrderOverTime();

        /**
         * 查询当前服务工单的报修人是否为e路康明斯用户
         * 如果用户不存在，则工单不需要进入待用户评价状态，如果用户存在，则工单需要进入待用户评价状态
         */
        WorkOrderT workOrderT = workOrderTDao.getWorkOrderTByOrderId(workOrderId);
        String phone = workOrderT.getCustomerPhone();

        List<UserT> userTList = loginDao.getUserByPhone(phone);
        if (CollectionUtils.isEmpty(userTList)) {
            // 工单报修人不在系统中，下一个状态为服务完成
            reason.setOrderStatus(14);
        } else {
            // 工单报修人在系统中，下一个状态为待用户评价
            reason.setOrderStatus(13);
        }


        UserT userT = UserThreadLocal.get();
        reason.setOrderId(workOrderId);
        reason.setType(overTimeType);
        reason.setReasonKey(reasonKey);

        if (StringUtils.isEmpty(reasonMessage)) {
            reasonMessage = workOrderOverTimeReasonDao.getReasonMessageByReasonKey(reasonKey);
        }

        reason.setReasonMessage(reasonMessage);
        reason.setReasonType(reasonType);
        reason.setPartInfo(partInfo);
        reason.setUserId(userT.getId());
        reason.setCreator(userT.getId());
        reason.setCreateTime(LocalTimeUtil.getRealCurrentTime());

        // 判断当前服务工单有没有上传超时原因
        WorkOrderOverTime woOverTime = workOrderOverTimeReasonDao.getOverTimeReasonByOrderIdAndType(workOrderId, overTimeType);

        if (null == woOverTime) {
            workOrderOverTimeReasonDao.insertSelective(reason);
        } else {
            reason.setId(woOverTime.getId());
            workOrderOverTimeReasonDao.updateByPrimaryKey(reason);
        }

        // 同步超时原因到CRM
        if (StringUtils.isNotEmpty(workOrderT.getOrderNoCrm())) {

            Map<String, Object> map = new HashMap<>();
            map.put("CRMNo", workOrderT.getOrderNoCrm());
            map.put("OverTimeReason", reasonMessage);
            CRMResponeEntity crmResponse = CRMApiUtils.getCRMServiceApi().syncOverTimeReasonToXCECCRM(map);
            if (crmResponse.getStatus() != 0) {
                throw new RuntimeException("超时原因同步CRM失败");
            }
        }

        /**
         * 当超时原因上传成功后，Redis加入已经上传超时原因的标识，当用户再次点击维修完成时，则不需要再次上传超时原因
         */
        redisClientUtils.setObject(RedisKeys.overTimeWorkOrderTypeKey(workOrderId + "", overTimeType), overTimeType, 60 * 60 * 24 * 30);
        ParameterTool.writeSuccessResponse(response);
    }


    @Override
    public void workOrderReason(Map<String, Object> map) {
        HttpServletResponse response = (HttpServletResponse) map.get("response");
        Integer type = MapUtils.getInteger(map, "type");
        List<Map<String, Object>> list = (List<Map<String, Object>>) redisClientUtils.getObject(RedisKeys.workOrderReasonKey(type));
        if (CollectionUtils.isEmpty(list)) {
            //获取超时原因列表，并放入redis中
            list = workOrderReasonDao.getWorkOrderReason(type);
            if (CollectionUtils.isNotEmpty(list)) {
                redisClientUtils.setObject(RedisKeys.workOrderReasonKey(type), list, 300);
            }
        }
        // TODO: 2019/9/2 待增加角色验证
        Map<String, Object> data = new HashMap<>();
        List<Map<String, Object>> reasonList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (Map<String, Object> sub : list) {
                Map<String, Object> result = new HashMap<>();
                result.put("reasonKey", MapUtils.getInteger(sub, "ReasonKey"));
                result.put("reasonMessage", MapUtils.getString(sub, "ReasonMessage"));
                result.put("reasonType", MapUtils.getInteger(sub, "ReasonType"));
                reasonList.add(result);
            }
        }
        data.put("reasonList", reasonList);
        ParameterTool.writeSuccessResponse(response, data);
    }

    private Map<String, Object> getSyncMap(Map<String, Object> workOrderMap, Map<String, Object> map) {
        Map<String, Object> syncMap = new HashMap<>();
        // 基本信息
        syncMap.put("orderNo", MapUtils.getString(workOrderMap, "OrderNo"));
        syncMap.put("CRMNo", MapUtils.getString(workOrderMap, "OrderNoCrm"));
        syncMap.put("billStatus", MapUtils.getInteger(workOrderMap, "OrderStatus"));
        syncMap.put("actionTime", LocalTimeUtil.getRealCurrentTime());
        // 超时原因
        String reasonMessage = MapUtils.getString(map, "reasonMessage");
        if (StringUtils.isEmpty(reasonMessage)) {
            Integer reasonKey = MapUtils.getInteger(map, "reasonKey");
            Map<String, Object> reasonMap = workOrderReasonDao.getWorkOrderReasonByReasonKey(reasonKey);
            reasonMessage = MapUtils.getString(reasonMap, "ReasonMessage");
        }
        syncMap.put("timeOutReason", reasonMessage);
        // 缺失零件信息
        List<Map<String, Object>> partMapList = new ArrayList<>();
        String partInfo = MapUtils.getString(map, "partInfo");
        if (StringUtils.isNotEmpty(partInfo)) {
            try {
                String[] part = partInfo.split(";");
                for (int i = 0; i < part.length; i++) {
                    String[] subPart = part[i].split(",");
                    Map<String, Object> partMap = new HashMap<>();
                    partMap.put("renewalPartNo", subPart[0]);
                    partMap.put("renewalPartName", subPart[1]);
                    partMap.put("quantity", subPart[2]);
                    partMapList.add(partMap);
                }
            } catch (Exception e) {
                log.error("解析零件信息发生异常，零件信息：" + partInfo + "；异常信息：" + e);
            }
        }
        syncMap.put("lackOfPart", partMapList);
        return syncMap;
    }

    /**
     * 获取工单编号
     *
     * @param map
     * @return
     */
    public String getOrderNo(Map<String, Object> map) {
        String num = SerialNumberUtil.getSerialNumber("WO");
        return num;
    }



    /**
     * 将工单信息同步至CRM(由于CRM接口与APP接口的字段名称不一致，所以要进行相关字段的转换)
     *
     * @param map
     * @param source 工单来源（0：客户，1：服务站）
     * @return
     */
    public Map<String, Object> APP2CRM_WorkOrder_Convert(Map<String, Object> map, int source, String serviceChannel) {
        Map<String, Object> newMap = new HashMap<String, Object>();
        if ("DCEC".equals(serviceChannel) || "XCEC".equals(serviceChannel)) {
            if ("XCEC".equals(serviceChannel) && MapUtils.getIntValue(map, "OrderType", -1) == 1) {
                //xcec售时工单走这套转换逻辑
                if (map.containsKey("ESN")) {
                    newMap.put("ESN", map.get("ESN"));
                }
                if (map.containsKey("salesServiceType")) {
                    newMap.put("salesServiceType", map.get("salesServiceType"));
                }
                if (map.containsKey("AccountId")) {
                    newMap.put("accountId", map.get("AccountId"));
                }
                if (map.containsKey("WarrantyStartDate")) {
                    newMap.put("procurementTime", map.get("WarrantyStartDate"));
                }
                newMap.put("workHours", map.get("WorkHours"));
                newMap.put("workMileages", map.get("WorkMileages"));
                if (map.containsKey("CustomerName")) {
                    newMap.put("customerName", map.get("CustomerName"));
                }
                if (map.containsKey("CustomerPhone")) {
                    newMap.put("customerPhone", map.get("CustomerPhone"));
                }
                if (map.containsKey("EngineSeries")) {
                    newMap.put("series", map.get("EngineSeries"));
                }
                if (map.containsKey("EnginePurpose")) {
                    newMap.put("appArea", map.get("EnginePurpose"));
                }
                newMap.put("needGoOut", MapUtils.getIntValue(map, "IsOutside", -1));
                if (map.containsKey("Location")) {
                    newMap.put("faultLocation", map.get("Location"));
                }
                if (map.containsKey("LocLat")) {
                    newMap.put("faultLat", map.get("LocLat"));
                }
                if (map.containsKey("LocLon")) {
                    newMap.put("faultLon", map.get("LocLon"));
                }
                newMap.put("vehicleType", MapUtils.getInteger(map, "GoOutType", 4));
                newMap.put("remark", "");
                newMap.put("orderNo", MapUtils.getString(map, "OrderNo", ""));
                newMap.put("equipmentNo", MapUtils.getString(map, "VIN", ""));
                newMap.put("orderSource", MapUtils.getIntValue(map, "OrderSource", 1));
                newMap.put("serviceCar", MapUtils.getString(map, "ServiceCarNo", ""));
                newMap.put("faultDesc", MapUtils.getString(map, "CustomerComplaint", ""));
                newMap.put("creatPerson", MapUtils.getString(map, "ProcessorName", ""));
                newMap.put("creatTime", MapUtils.getString(map, "CreateTime", ""));
                newMap.put("stationNo", "");
                if (map.containsKey("ServiceStationId")) {
                    //根据页面传给我的服务站ID查询服务站编号
                    Map<String, Object> serviceMap = workOrderRepairDao.getStationNoById(map);
                    if (MapUtils.isNotEmpty(serviceMap)) {
                        String businessNo = MapUtils.getString(serviceMap, "BusinessNo", "");
                        if (StringUtils.isNotEmpty(businessNo)) {
                            newMap.put("stationNo", businessNo);
                        }
                    }
                }
            } else {
                if (map.containsKey("OrderNo")) {
                    newMap.put("orderNo", map.get("OrderNo"));
                }
                if (map.containsKey("ESN")) {
                    newMap.put("ESN", map.get("ESN"));
                }
                if (map.containsKey("VIN")) {
                    newMap.put("equipmentNo", map.get("VIN"));
                } else {
                    newMap.put("equipmentNo", "");
                }
                if (map.containsKey("CustomerName")) {
                    newMap.put("customerName", map.get("CustomerName"));
                }
                if (map.containsKey("CustomerPhone")) {
                    newMap.put("customerPhone", map.get("CustomerPhone"));
                }
                if (map.containsKey("Location")) {
                    newMap.put("faultLocation", map.get("Location"));
                }
                if (map.containsKey("LocLat")) {
                    newMap.put("faultLat", map.get("LocLat"));
                }
                if (map.containsKey("LocLon")) {
                    newMap.put("faultLon", map.get("LocLon"));
                }
                if (map.containsKey("ServiceCarNo")) {
                    newMap.put("serviceCar", map.get("ServiceCarNo"));
                } else {
                    newMap.put("serviceCar", "");
                }
                if (map.containsKey("IsOutside")) {
                    newMap.put("needGoOut", map.get("IsOutside"));
                } else {
                    newMap.put("needGoOut", -1);
                }
                if (map.containsKey("CustomerComplaint")) {
                    newMap.put("faultDesc", map.get("CustomerComplaint"));
                }
                newMap.put("stationNo", "");
                if (map.containsKey("ServiceStationId")) {
                    //根据页面传给我的服务站ID查询服务站编号
                    Map<String, Object> serviceMap = new HashMap<String, Object>();
                    serviceMap = workOrderRepairDao.getStationNoById(map);
                    if (null != serviceMap && serviceMap.size() > 0) {
                        if (!"".equals(MapUtils.getString(serviceMap, "BusinessNo", ""))) {
                            newMap.put("stationNo", serviceMap.get("BusinessNo"));
                        }
                    }
                }
                if (map.containsKey("OrderChannel")) {
                    newMap.put("serviceChannel", map.get("OrderChannel"));
                }
                //服务站还是用户报修
                newMap.put("orderSource", source);

                if (map.containsKey("ProcessorName")) {
                    newMap.put("creatPerson", map.get("ProcessorName"));
                }
                if (map.containsKey("CreateTime")) {
                    newMap.put("creatTime", map.get("CreateTime"));
                }
                newMap.put("workHours", MapUtils.getString(map, "WorkHours", ""));
                newMap.put("workMileages", MapUtils.getString(map, "WorkMileages", ""));
                newMap.put("remark", "");

                /**
                 * Amt需求 新增参数
                 */
                /**
                 * DCEC amt工单需求 2022-12-26
                 * 新增3个参数
                 * 【变速箱序列号】，amtNo -- AmtNo
                 * 【保修性质】，warrantyNature -- WarrantyNature
                 * 【故障发生时间】，faultHappenTime -- FaultHappenTime
                 */
                newMap.put("amtNo", MapUtils.getString(map, "AmtNo"));
                newMap.put("warrantyNature", MapUtils.getString(map, "WarrantyNature"));
                newMap.put("faultHappenTime", MapUtils.getString(map, "FaultHappenTime"));

            }
        } else {
            newMap.put("orderNo", MapUtils.getString(map, "OrderNo", ""));
            newMap.put("ESN", MapUtils.getString(map, "ESN", ""));
            newMap.put("marketTypes", MapUtils.getString(map, "MarketType", ""));
            newMap.put("applications", MapUtils.getString(map, "Application", ""));
            newMap.put("warrantyStartDate", MapUtils.getString(map, "WarrantyStartDate", ""));
            newMap.put("equipmentNo", MapUtils.getString(map, "VIN", ""));
            newMap.put("vehicleCompany", MapUtils.getString(map, "OEMName", ""));
            newMap.put("manufactor", MapUtils.getString(map, "manufactor", ""));
            newMap.put("customerName", MapUtils.getString(map, "CustomerName", ""));
            newMap.put("customerPhone", MapUtils.getString(map, "CustomerPhone", ""));
            newMap.put("faultLat", MapUtils.getDouble(map, "LocLat", 0.0));
            newMap.put("faultLon", MapUtils.getDouble(map, "LocLon", 0.0));
            newMap.put("faultLocation", MapUtils.getString(map, "Location", ""));
            newMap.put("faultProvince", MapUtils.getString(map, "LocProvince", ""));
            newMap.put("faultCity", MapUtils.getString(map, "LocCity", ""));
            newMap.put("faultDesc", MapUtils.getString(map, "CustomerComplaint", ""));
            newMap.put("customerType", MapUtils.getString(map, "CustomerType", ""));
            newMap.put("customerUserID", MapUtils.getString(map, "CustomerId", ""));
            newMap.put("customerCompany", MapUtils.getString(map, "CustomerCompanyName", ""));
            newMap.put("customerCompanyProvince", MapUtils.getString(map, "CustomerCompanyProvince", ""));
            newMap.put("customerCompanyCity", MapUtils.getString(map, "CustomerCompanyCity", ""));
            newMap.put("workHours", MapUtils.getString(map, "WorkHours", ""));
            newMap.put("workMileages", MapUtils.getString(map, "WorkMileages", ""));
            //dbu公众号报单   crm的orderSource对应值为14   这里做转换
            if ("CCI".equals(serviceChannel) && source == 5) {
                source = 14;
            }
            newMap.put("orderSource", source);
            newMap.put("serviceCar", MapUtils.getString(map, "ServiceCarNo", ""));
            newMap.put("needGoOut", MapUtils.getInteger(map, "IsOutside", 0));
            if (map.containsKey("ServiceStationId")) {
                //根据页面传给我的服务站ID查询服务站编号
                Map<String, Object> serviceMap = workOrderRepairDao.getStationNoById(map);
                if (MapUtils.isNotEmpty(serviceMap)) {
                    newMap.put("stationNo", MapUtils.getString(serviceMap, "BusinessNo", ""));
                    newMap.put("stationName", MapUtils.getString(serviceMap, "StationName", ""));
                }
            } else {
                newMap.put("stationNo", "");
                newMap.put("stationName", "");
            }
            newMap.put("serviceChannel", serviceChannel);
            newMap.put("contactName", MapUtils.getString(map, "CustomerName", ""));
            newMap.put("contactPhone", MapUtils.getString(map, "CustomerPhone", ""));
            newMap.put("createTime", MapUtils.getString(map, "CreateTime", LocalTimeUtil.getRealCurrentTime()));
            newMap.put("declarationTime", MapUtils.getString(map, "UploadTime", ""));
            newMap.put("remark", "");
            newMap.put("directorName", MapUtils.getString(map, "directorName", ""));
            newMap.put("directorPhone", MapUtils.getString(map, "directorPhone", ""));
        }

        if ("CCEC".equals(serviceChannel)) {
            newMap.put("orderCategory", MapUtils.getString(map, "ComplainWorkOrderType"));
            newMap.put("isInsured", MapUtils.getString(map, "IsInsured"));
            newMap.put("estimateWarrantyStartDate", MapUtils.getString(map, "EstimateWarrantyStartDate"));
            newMap.put("serviceInitPlan", MapUtils.getString(map, "ServiceInitPlan"));
            newMap.put("goOutType", MapUtils.getString(map, "GoOutType"));
            newMap.put("contactName", MapUtils.getString(map, "CustomerName"));
            newMap.put("contactPhone", MapUtils.getString(map, "CustomerPhone"));
            newMap.put("requestType", MapUtils.getString(map, "RequestType"));
            newMap.put("faultLevel", MapUtils.getString(map, "FaultLevel"));
            newMap.put("sizeFailure", MapUtils.getString(map, "SizeFailure"));
            newMap.put("faultReason", MapUtils.getString(map, "FaultReason"));
            newMap.put("repairerType", MapUtils.getString(map, "RepairerType"));
        }

        if ("CCI".equals(serviceChannel)) {
            /**
             * 3.1.0需求
             * 修改了原来服务子类型的名称，CRM方不愿修改后端代码，因此在往CRM同步服务子类型的时候
             * 还需要把新的服务子类型名称映射成之前的旧名称  (⊙﹏⊙)b
             */
            String serviceSubtype = MapUtils.getString(map, "ServiceSubtype", "");
            if (StringUtils.isNotEmpty(serviceSubtype)) {
                serviceSubtype = Arrays.stream(serviceSubtype.split(";")).map(e -> {
                    switch (e) {
                        case "首次保养":
                            return "首保";
                        case "保养记录":
                            return "保养";
                        case "厂内服务":
                            return "BIS服务";
                        case "统修整改":
                            return "统修";
                        case "故障处理":
                            return "故障维修";
                        default:
                            return e;
                    }
                }).collect(Collectors.joining(";"));
            }


            // 2.8.0 DBU增加了服务子类型字段
            newMap.put("serviceSubtype", serviceSubtype);
            newMap.put("unifiedRepairNo", MapUtils.getString(map, "UnifiedRepairNo", ""));
            // 2.9.0 DBU增加了故障症状以及故障码字段
            newMap.put("faultCodes", MapUtils.getString(map, "FaultCodes", ""));
            newMap.put("symptomName", MapUtils.getString(map, "SymptomName", ""));
            //健康检查
            newMap.put("HealthExaminationCategory", MapUtils.getString(map, "HealthExaminationCategory", ""));
            //底盘号
            newMap.put("ChassisNumber", MapUtils.getString(map, "ChassisNumber", ""));
            //机组序列号
            newMap.put("GSN", MapUtils.getString(map, "GSN"));
            newMap.put("SellType", MapUtils.getString(map, "SellType"));
            if (map.containsKey("BookkeepingType")) {
                newMap.put("BookkeepingType", MapUtils.getString(map, "BookkeepingType"));
            }
        }
        return newMap;
    }


    /**
     * 将工单状态同步至CRM
     *
     * @return
     */
    public Map<String, Object> OrderStatusToCrmMap(Map<String, Object> orgOrderMap, Map<String, Object> map) {
        Map<String, Object> tbMap = new HashMap<String, Object>();
        tbMap.put("orderNo", orgOrderMap.get("OrderNo"));
        if (!"".equals(MapUtils.getString(orgOrderMap, "RelOrderIdOld", ""))) {
            tbMap.put("oldOrderNo", orgOrderMap.get("RelOrderIdOld"));
        } else {
            tbMap.put("oldOrderNo", "");
        }
        if (!"".equals(MapUtils.getString(orgOrderMap, "OrderNoCrm", ""))) {
            tbMap.put("CRMNo", orgOrderMap.get("OrderNoCrm"));
        } else {
            tbMap.put("CRMNo", "");
        }
        tbMap.put("billStatus", "15");

        tbMap.put("stationNo", "");
        map.put("OrderChannel", MapUtils.getInteger(orgOrderMap, "OrderChannel", 0));
        if (map.containsKey("ServiceStationId")) {
            //根据页面传给我的服务站ID查询服务站编号
            Map<String, Object> serviceMap = new HashMap<String, Object>();
            serviceMap = workOrderRepairDao.getStationNoById(map);
            if (null != serviceMap && serviceMap.size() > 0) {
                if (!"".equals(MapUtils.getString(serviceMap, "BusinessNo", ""))) {
                    tbMap.put("stationNo", serviceMap.get("BusinessNo"));
                }
            }
        }
        tbMap.put("actionTime", LocalTimeUtil.getRealCurrentTime());
        tbMap.put("directorName", map.get("ProcessorName"));
        tbMap.put("directorPhone", map.get("ProcessorPhone"));
        //查询处理主副技师
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        list = workOrderRepairDao.getServiceAssociateTechnician(orgOrderMap.get("OrderId").toString());
        if (null != list && list.size() > 0) {
            String assistEngineerName = "";
            String engineerPhone = "";
            for (Map<String, Object> mmap : list) {
                assistEngineerName += mmap.get("UserName") + ",";
                engineerPhone += mmap.get("Phone") + ",";
            }
            if (assistEngineerName.length() > 1) {
                assistEngineerName = assistEngineerName.substring(0, assistEngineerName.length() - 1);
            }
            if (engineerPhone.length() > 1) {
                engineerPhone = engineerPhone.substring(0, engineerPhone.length() - 1);
            }
            tbMap.put("assistEngineerName", assistEngineerName);
            tbMap.put("engineerPhone", engineerPhone);
        }
        if (!"".equals(MapUtils.getString(map, "GuessDistance", ""))) {
            tbMap.put("planMileage", map.get("GuessDistance"));
        }
        if (!"".equals(MapUtils.getString(map, "RealDistance", ""))) {
            tbMap.put("travelMileage", map.get("RealDistance"));
        }
        if (!"".equals(MapUtils.getString(map, "AdjustDistance", ""))) {
            tbMap.put("reviseMileage", map.get("AdjustDistance"));
        }

        return tbMap;
    }

	public Map<String,Object> syncOrderStatusMap(Map<String,Object> orderMap,Integer orderStatus){
		Map<String,Object> syncMap = new HashMap<>();
		syncMap.put("orderNo", MapUtils.getString(orderMap,"OrderNo"));
		syncMap.put("CRMNo", MapUtils.getString(orderMap,"OrderNoCrm"));
		syncMap.put("refuseReason",MapUtils.getString(orderMap,"CancelReason",""));
		syncMap.put("billStatus", orderStatus);
		syncMap.put("actionTime", LocalTimeUtil.getRealCurrentTime());

		return syncMap;
	}

    /**
     * sprint24     更新  gsn和下拉原因
     *
     * @param request
     * @return
     */
    @Override
    public ModelAndView updateGsnOrSymptomName(HttpServletRequest request, HttpServletResponse response) {

        Map<String, Object> map = null;
        try {
            map = ParameterTool.getParameterRequest(request, true);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        if (null == map) {
            ParameterTool.writeResponse(response, SMSEnum.type18.getIndex(), "请输入GSN或者故障原因");
        }
        Long id = MapUtils.getLongValue(map, "ID");
        if (null == id) {
            ParameterTool.writeResponse(response, SMSEnum.type18.getIndex(), "请输入ID");
        }
        int i = workOrderRepairDao.updateWorkOrderGsn(map);
        if (i > 0) {
            WorkOrderT workOrderTByOrderId = workOrderTDao.getWorkOrderTByOrderId(id);
            if (null != workOrderTByOrderId) {
                //同步给crm
                try {
                    Map<String, Object> tbMap = new HashMap<String, Object>();
                    tbMap.put("orderNo", workOrderTByOrderId.getOrderNo());
                    String gsn = MapUtil.getMapValue(map, "GSN");
                    if (StringUtils.isNotBlank(gsn)) {
                        tbMap.put("GSN", gsn);
                    }
                    String SymptomName = MapUtil.getMapValue(map, "SymptomName");
                    if (StringUtils.isNotBlank(SymptomName)) {
                        tbMap.put("SymptomName", SymptomName);
                    }
                    CRMResponeEntity CRMres = CRMApiUtils.getCRMServiceApi().syncOrderStatusToCrm(CRMServiceConst.DBU_TEST, platformServiceDao, redisClientUtils, tbMap,null);
                    if (CRMres.getStatus() != 0) {
                        //APP同步工单信息到CRM系统失败
                        log.error("用户在线报修同步工单信息至CRM失败GSN，状态：" + CRMres.getStatus() + "，用户信息:" + CRMres.getMessage());
                    }
                } catch (Exception e) {
                    //APP同步工单信息到CRM系统失败
                    log.error("用户在线报修同步工单信息至CRM失败GSN：" + e.getMessage(), e);
                }
            }
            ParameterTool.writeResponse(response, SMSEnum.type00.getIndex(), SMSEnum.type00.getName());
        } else {
            ParameterTool.writeResponse(response, SMSEnum.type99.getIndex(), SMSEnum.type99.getName());
        }
        return null;
    }
}
